package com.aizuda.boot.modules.business.contract.service.impl;

import com.aizuda.boot.modules.business.contract.dto.SingleResponse;
import com.aizuda.boot.modules.business.contract.dto.UserInfo;
import com.aizuda.boot.modules.business.contract.entity.*;
import com.aizuda.boot.modules.business.contract.entity.dto.*;
import com.aizuda.boot.modules.common.constant.enums.ContractStatusEnum;
import com.aizuda.boot.modules.business.contract.entity.vo.*;
import com.aizuda.boot.modules.common.constant.enums.ResponseCodeEnum;
import com.aizuda.boot.modules.business.contract.mapper.*;
import com.aizuda.boot.modules.business.contract.service.*;
import com.aizuda.boot.modules.business.contract.util.AuthUtil;
import com.aizuda.boot.modules.business.contractNumber.domain.ContractNumberEvent;
import com.aizuda.boot.modules.common.constant.enums.GenerateTimingEnums;
import com.aizuda.boot.modules.business.counterparty.service.CounterpartyService;
import com.aizuda.boot.modules.business.negotiation.mapper.ContractNegotiationParticipantMapper;
import com.aizuda.boot.modules.common.MessageEvent;
import com.aizuda.boot.modules.business.contract.entity.dto.MyContractQueryDTO;
import com.aizuda.boot.modules.business.negotiation.mapper.ContractNegotiationInstanceMapper;
import com.aizuda.boot.modules.business.negotiation.entity.ContractNegotiationInstanceEntity;
import com.aizuda.boot.modules.business.negotiation.entity.ContractNegotiationParticipantEntity;
import com.aizuda.boot.modules.common.constant.enums.SystemFieldsEnum;
import com.aizuda.boot.modules.system.entity.SysDepartment;
import com.aizuda.boot.modules.system.entity.SysUser;
import com.aizuda.bpm.engine.model.DynamicAssignee;
import com.aizuda.bpm.engine.model.ModelHelper;
import com.aizuda.bpm.engine.model.NodeAssignee;
import com.aizuda.service.web.UserSession;
import com.aizuda.boot.modules.business.negotiation.service.ContractNegotiationConfigService;
import com.aizuda.boot.modules.business.counterparty.entity.BankInfoEntity;
import com.aizuda.boot.modules.business.counterparty.entity.CounterpartyInfoEntity;
import com.aizuda.boot.modules.business.counterparty.entity.LegalEntityDetailEntity;
import com.aizuda.boot.modules.common.constant.enums.CertificateTypeEnum;
import com.aizuda.boot.modules.common.constant.enums.CounterpartyNatureEnum;
import com.aizuda.boot.modules.common.constant.enums.CounterpartyTypeEnum;
import com.aizuda.boot.modules.business.counterparty.mapper.BankInfoMapper;
import com.aizuda.boot.modules.business.counterparty.mapper.CounterpartyInfoMapper;
import com.aizuda.boot.modules.business.counterparty.mapper.LegalEntityDetailMapper;
import com.aizuda.boot.modules.business.dict.service.CountryDictService;
import com.aizuda.boot.modules.file.domain.entity.ContractFileEntity;
import com.aizuda.boot.modules.file.domain.vo.FileVO;
import com.aizuda.boot.modules.file.service.FileInfoService;
import com.aizuda.boot.modules.file.util.FileConversionUtil;
import com.aizuda.boot.modules.business.contract_operation_log.domain.entity.ContractOperationLog;
import com.aizuda.boot.modules.common.constant.enums.WorkFlowTypeEnums;
import com.aizuda.boot.modules.common.constant.enums.ActionTypeEnums;
import com.aizuda.boot.modules.common.constant.enums.SourceTypeEnums;
import com.aizuda.boot.modules.business.contract_operation_log.service.ContractOperationLogService;
import com.aizuda.boot.modules.third.wps.mapper.FileHistoryMapper;
import com.aizuda.boot.modules.third.wps.domain.entity.FileHistory;
import com.aizuda.boot.modules.business.contract.entity.ContractTypeEntity;
import com.aizuda.boot.modules.business.performance.mapper.ContractTypeMapper;
import com.aizuda.boot.modules.business.template.entity.ContractTemplateUsageEntity;
import com.aizuda.boot.modules.business.template.mapper.ContractTemplateUsageMapper;
import com.aizuda.boot.modules.business.template.service.ContractTemplateService;
import com.aizuda.boot.modules.business.template.entity.vo.ContractTemplateRespDTO;
import com.aizuda.boot.modules.system.service.ISysDepartmentService;
import com.aizuda.boot.modules.system.service.ISysUserDepartmentService;
import com.aizuda.boot.modules.system.service.ISysUserService;
import com.aizuda.boot.modules.system.service.ISysUserRoleService;
import com.aizuda.boot.modules.business.permission.service.RoleDataIsolationService;
import com.aizuda.boot.modules.business.permission.domain.entity.RoleDataIsolationEntity;
import com.aizuda.boot.modules.common.constant.enums.DataType;
import com.aizuda.boot.modules.common.constant.enums.ContractScopeTypeEnums;
import com.aizuda.boot.modules.common.constant.enums.PermissionStatusType;
import com.aizuda.boot.modules.common.constant.enums.ValidityType;
import com.aizuda.boot.modules.file.service.IContractFileService;
import com.aizuda.boot.modules.flw.entity.dto.ProcessStartDTO;
import com.aizuda.boot.modules.flw.flow.FlowHelper;
import com.aizuda.boot.modules.flw.service.IFlwProcessService;
import com.aizuda.bpm.engine.core.FlowCreator;
import com.aizuda.bpm.engine.model.NodeModel;
import com.aizuda.boot.modules.system.entity.SysUserDepartment;
import com.aizuda.boot.modules.system.mapper.SysDepartmentMapper;
import com.aizuda.bpm.engine.entity.FlwProcess;
import com.aizuda.bpm.mybatisplus.mapper.FlwProcessMapper;
import com.aizuda.boot.modules.business.contract.entity.ContractWorkflowDepartment;
import com.aizuda.boot.modules.business.contract.entity.ContractTypeDepartmentEntity;
import com.aizuda.boot.modules.business.contract.mapper.ContractWorkflowMapper;
import com.aizuda.boot.modules.business.contract.entity.ContractWorkflowEntity;
import com.aizuda.boot.modules.business.employee.domain.request.EmployeeQueryById;
import com.aizuda.boot.modules.business.employee.domain.response.EmployeeQueryShowVO;
import com.aizuda.boot.modules.flw.mapper.FlowlongMapper;
import com.aizuda.bpm.engine.FlowLongEngine;
import com.aizuda.boot.modules.system.entity.vo.department.DepartmentInfoDTO;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;
import com.aizuda.boot.modules.business.contract.service.ContractFieldService;


/**
 * 合同服务实现类
 */
@Slf4j
@Service
public class ContractServiceImpl extends ServiceImpl<ContractMapper, ContractEntity> implements ContractService {

    // 用于在方法间传递当前用户的数据权限信息
    private static final ThreadLocal<ContractScopeTypeEnums> currentUserPermission = new ThreadLocal<>();
    private static final ThreadLocal<List<Long>> currentUserDepartments = new ThreadLocal<>();
    @Resource
    private ContractMapper contractMapper;
    @Resource
    private ContractModuleMapper contractModuleMapper;
    @Resource
    private ContractFieldValueMapper contractFieldValueMapper;
    @Resource
    private ContractFieldMapper contractFieldMapper;
    @Resource
    private ContractModuleFieldMapper contractModuleFieldMapper;
    @Resource
    private WorkflowNodeMapper workflowNodeMapper;
    @Resource
    private ContractWorkflowTypeMapper contractWorkflowTypeMapper;
    @Resource
    private ContractTypeMapper contractTypeMapper;
    @Resource
    private EmployeeRecentContractTypeMapper employeeRecentContractTypeMapper;
    @Resource
    private ContractTemplateUsageMapper contractTemplateUsageMapper;
    @Resource
    private EmployeeTableHeaderService employeeTableHeaderService;
    @Resource
    private LegalEntityDetailMapper legalEntityDetailMapper;
    @Resource
    private CounterpartyInfoMapper counterpartyInfoMapper;
    @Resource
    private BankInfoMapper bankInfoMapper;
    @Resource
    private CountryDictService countryDictService;
    @Resource
    private FileInfoService fileInfoService;
    @Resource
    private ISysDepartmentService sysDepartmentService;
    @Resource
    private SysDepartmentMapper sysDepartmentMapper;
    @Resource
    private ISysUserService sysUserService;
    @Resource
    private ContractWorkflowService contractWorkflowService;
    @Resource
    private ISysUserDepartmentService sysUserDepartmentService;
    @Resource
    private ISysUserRoleService sysUserRoleService;
    @Resource
    private RoleDataIsolationService roleDataIsolationService;
    @Resource
    private ContractNegotiationConfigService contractNegotiationConfigService;
    @Resource
    private IContractFileService contractFileService;
    @Resource
    private CounterpartyService counterpartyService;
    @Resource
    private ContractOperationLogService contractOperationLogService;
    @Resource
    private FileHistoryMapper fileHistoryMapper;
    @Resource
    private ContractTemplateService contractTemplateService;
    @Resource
    private IFlwProcessService flwProcessService;
    @Resource
    private FlwProcessMapper flwProcessMapper;
    @Resource
    private ContractWorkflowMapper contractWorkflowMapper;
    @Resource
    private ContractWorkflowDepartmentService contractWorkflowDepartmentService;
    @Resource
    private ContractTypeDepartmentService contractTypeDepartmentService;
    @Resource
    private ContractNegotiationInstanceMapper contractNegotiationInstanceMapper;
    @Resource
    private FlowlongMapper flowlongMapper;
    @Resource
    private FlowLongEngine flowLongEngine;
    @Resource
    private ContractAttachmentConfirmMapper contractAttachmentConfirmMapper;
    @Resource
    private ContractNegotiationParticipantMapper contractNegotiationParticipantMapper;
    @Resource
    private org.springframework.context.ApplicationEventPublisher applicationEventPublisher;
    @Resource
    private ContractTypeService contractTypeService;
    @Resource
    private ContractServiceOptimized contractServiceOptimized;
    @Resource
    private ContractTypeUserService contractTypeUserService;
    @Resource
    private ContractFieldService contractFieldService;

    @Override
    public Page<ContractDTO> getContractList(ContractListReqDTO request) {
        Page<ContractDTO> page = new Page<>();

        // 1. 查询"申请人"字段ID
        Long handlerFieldId = getFieldIdByName("申请人");
        if (handlerFieldId == null) {
            throw new RuntimeException("申请人字段未定义");
        }

        // 2. 构建查询条件
        LambdaQueryWrapper<ContractEntity> queryWrapper = new LambdaQueryWrapper<>();

        // 基础查询条件
        buildBasicQueryConditions(queryWrapper, request);

        // 合同状态查询条件（特殊处理）
        buildContractStatusConditions(queryWrapper, request);

        // 查询符合基础条件的合同
        List<ContractEntity> contracts = contractMapper.selectList(queryWrapper);

        // 3. 动态字段过滤
        List<ContractEntity> filteredContracts = filterByDynamicFields(contracts, request);

        // 4. 查询所有启用的模块
        List<ContractModuleEntity> modules = contractModuleMapper.selectEnabledModules();
        Map<Integer, ContractModuleEntity> moduleMap = modules.stream()
                .collect(Collectors.toMap(ContractModuleEntity::getId, m -> m));

        // 5. 构建结果
        List<ContractDTO> contractDTOs = filteredContracts.stream().map(contract -> {
            ContractDTO dto = new ContractDTO();
            BeanUtils.copyProperties(contract, dto);
            // 设置审批流程实例ID
            dto.setInstanceId(contract.getApprovalInstanceId());
            // 移除modules字段，不再需要
            // 从动态字段中获取合同类型名称列表
            dto.setContractTypeNames(getContractTypeNamesFromDynamicFields(contract.getId()));

            // 设置法人实体详情和交易方详情（与合同详情保持一致）
            setLegalEntityAndCounterpartyDetails(dto, contract.getId());

            // 从动态字段获取主合同文件信息（字段ID=20）
            setMainContractFileInfo(dto, contract.getId());

            return dto;
        }).collect(Collectors.toList());

        // todo 添加审批详情（如果需要）

        // 7. 添加字段值信息
        for (ContractDTO contractDTO : contractDTOs) {
            contractDTO.setFields(contractFieldValueMapper.getFieldValuesWithFieldInfo(contractDTO.getId()));

            // 7.1 单独查询并设置fieldOptions
            if (contractDTO.getFields() != null && !contractDTO.getFields().isEmpty()) {
                // 收集所有字段ID
                List<Long> fieldIds = contractDTO.getFields().stream()
                        .map(ContractDTO.ModuleDTO.FieldDTO::getId)
                        .collect(Collectors.toList());

                // 批量查询字段信息
                List<ContractFieldEntity> fieldEntities = contractFieldMapper.selectBatchIds(fieldIds);
                Map<Long, String> fieldOptionsMap = fieldEntities.stream()
                        .filter(f -> f.getFieldOptions() != null)
                        .collect(Collectors.toMap(f -> f.getId().longValue(), ContractFieldEntity::getFieldOptions));
                Map<Long, String> fieldCodeMap = fieldEntities.stream()
                        .collect(Collectors.toMap(f -> f.getId().longValue(), f -> f.getCode() != null ? f.getCode() : ""));

                // 设置fieldOptions和code
                for (ContractDTO.ModuleDTO.FieldDTO field : contractDTO.getFields()) {
                    // 设置code字段
                    String code = fieldCodeMap.get(field.getId());
                    if (code != null) {
                        field.setCode(code);
                    }

                    // 设置fieldOptions
                    String optionsJson = fieldOptionsMap.get(field.getId());
                    if (optionsJson != null && !optionsJson.trim().isEmpty()) {
                        try {
                            Map<String, Object> optionsMap = JSON.parseObject(optionsJson);
                            field.setFieldOptions(optionsMap);
                            log.debug("设置fieldOptions - 字段ID: {}, 字段名: {}, code: {}, options: {}",
                                    field.getId(), field.getFieldName(), field.getCode(), optionsMap);
                        } catch (Exception e) {
                            log.error("解析fieldOptions失败，字段ID: {}, JSON: {}", field.getId(), optionsJson, e);
                        }
                    }
                }
            }

            // 8. 处理字段值和字段描述
            processFieldValuesAndDescriptions(contractDTO);
        }

        // 9. 填充申请人字段
        fillApplicantNames(contractDTOs);

        // 10. 按时间排序（最新的在前面）
        contractDTOs.sort((c1, c2) -> {
            LocalDateTime time1 = c1.getUpdatedAt() != null ? c1.getUpdatedAt() : c1.getCreatedAt();
            LocalDateTime time2 = c2.getUpdatedAt() != null ? c2.getUpdatedAt() : c2.getCreatedAt();

            if (time1 == null && time2 == null) return 0;
            if (time1 == null) return 1;  // 没有时间的排在后面
            if (time2 == null) return -1; // 没有时间的排在后面

            return time2.compareTo(time1); // 降序排列，最新的在前面
        });

        // 11. 手动分页
        int total = contractDTOs.size();
        int fromIndex = (int) ((request.getPageIndex() - 1) * request.getPageSize());
        int toIndex = Math.min(fromIndex + request.getPageSize(), total);
        List<ContractDTO> pagedContracts = Collections.emptyList();

        if (fromIndex < total) {
            pagedContracts = contractDTOs.subList(fromIndex, toIndex);
        }

        // 设置分页数据
        page.setTotal(total);
        page.setRecords(pagedContracts);

        // 清理ThreadLocal，避免内存泄漏
        currentUserPermission.remove();
        currentUserDepartments.remove();

        return page;
    }

    /**
     * 构建基础查询条件
     */
    private void buildBasicQueryConditions(LambdaQueryWrapper<ContractEntity> queryWrapper, ContractListReqDTO request) {
        // 1. 租户隔离：只查询当前用户有权限的租户下的合同 - 修改逻辑：优先使用当前租户，如果为空则使用租户列表
        UserInfo currentUser = AuthUtil.getCurrentUser();
        String currentSysTenantKey = currentUser != null ? currentUser.getSysTenantKey() : null;

        if (currentSysTenantKey != null && !currentSysTenantKey.trim().isEmpty()) {
            // 如果当前用户有明确的sysTenantKey，只查询该租户下的数据
            queryWrapper.eq(ContractEntity::getSysTenantKey, currentSysTenantKey);
            log.debug("使用当前租户过滤合同列表：{}", currentSysTenantKey);
        } else {
            // 如果sysTenantKey为null或空，使用原有逻辑（查询用户有权限的所有租户）
            List<String> userTenantKeys = AuthUtil.getUserTenantKeys();
            if (userTenantKeys != null && !userTenantKeys.isEmpty()) {
                queryWrapper.in(ContractEntity::getSysTenantKey, userTenantKeys);
                log.debug("使用租户列表过滤合同列表：{}", userTenantKeys);
            } else if (userTenantKeys == null) {
                // null 表示超级管理员，不限制租户
                log.debug("超级管理员访问，不限制租户");
            } else {
                // 空列表表示没有任何租户权限
                queryWrapper.eq(ContractEntity::getSysTenantKey, "NO_PERMISSION");
                log.warn("用户没有任何租户权限");
            }
        }

        // 2. 数据权限认证：只有全部合同查询（queryType=0）才需要应用数据权限
        if (request.getQueryType().getCode() == 0 && currentUser != null && currentUser.getId() != null) {
            applyDataPermissionFilter(queryWrapper, currentUser.getId());
        }

        // 3. 排除协商中的合同
        queryWrapper.ne(ContractEntity::getCurrentStatus, "IN_NEGOTIATION");

        // 4. 根据查询类型设置基础条件
        if (request.getQueryType().getCode() == 1 || request.getQueryType().getCode() == 2) {
            // 我的合同或我的草稿需要根据用户ID过滤
            if (request.getUserId() == null) {
                throw new RuntimeException("查询我的合同时用户ID不能为空");
            }
            // 注意：申请人的过滤逻辑在 filterByDynamicFields 方法中自动处理
        }

        if (request.getQueryType().getCode() == 2) {
            // 我的草稿：只返回草稿状态的合同
            queryWrapper.eq(ContractEntity::getCurrentStatus, "DRAFT");
        } else {
            // 全部合同（0）或我的合同（1）：排除草稿状态的合同
            queryWrapper.ne(ContractEntity::getCurrentStatus, "DRAFT");
        }

        // 其他基础字段查询条件可以在这里添加
    }

    /**
     * 应用数据权限过滤
     *
     * @param queryWrapper 查询包装器
     * @param userId       用户ID
     */
    private void applyDataPermissionFilter(LambdaQueryWrapper<ContractEntity> queryWrapper, Long userId) {
        try {
            log.debug("开始应用数据权限过滤，用户ID: {}", userId);

            // 1. 查询当前用户的角色ID列表
            List<Long> roleIds = sysUserRoleService.listRoleIdsByUserId(userId);
            log.debug("用户 {} 的角色ID列表: {}", userId, roleIds);

            // 2. 查询当前用户的部门ID列表
            List<Long> departmentIds = sysUserDepartmentService.listDepartmentIdsByUserId(userId);
            log.debug("用户 {} 的部门ID列表: {}", userId, departmentIds);

            // 3. 查询数据权限并获取最高权限级别
            ContractScopeTypeEnums highestPermission = getHighestContractPermission(userId, roleIds, departmentIds);
            log.debug("用户 {} 的最高合同权限级别: {}", userId, highestPermission);

            // 4. 将权限信息保存到ThreadLocal中，供后续过滤使用
            currentUserPermission.set(highestPermission);
            currentUserDepartments.set(departmentIds);

            // 5. 根据权限级别应用过滤条件
            applyPermissionBasedFilter(queryWrapper, userId, departmentIds, highestPermission);

        } catch (Exception e) {
            log.error("应用数据权限过滤失败，用户ID: {}", userId, e);
            // 出现异常时，清理ThreadLocal并默认只能查看自己的合同（最严格的权限）
            currentUserPermission.remove();
            currentUserDepartments.remove();
            queryWrapper.eq(ContractEntity::getId, -1); // 查询不存在的ID，返回空结果
        }
    }

    /**
     * 获取用户的最高合同权限级别
     *
     * @param userId        用户ID
     * @param roleIds       角色ID列表
     * @param departmentIds 部门ID列表
     * @return 最高权限级别
     */
    private ContractScopeTypeEnums getHighestContractPermission(Long userId, List<Long> roleIds, List<Long> departmentIds) {
        log.debug("开始查询用户 {} 的数据权限，角色ID: {}, 部门ID: {}", userId, roleIds, departmentIds);

        // 基础查询条件：数据类型为CONTRACT且权限状态为ENABLE
        LambdaQueryWrapper<RoleDataIsolationEntity> baseWrapper = new LambdaQueryWrapper<>();
        baseWrapper.eq(RoleDataIsolationEntity::getDataType, DataType.CONTRACT)
                .eq(RoleDataIsolationEntity::getPermissionStatus, PermissionStatusType.ENABLE);

        List<RoleDataIsolationEntity> allPermissions = new ArrayList<>();

        // 1. 查询角色权限
        if (roleIds != null && !roleIds.isEmpty()) {
            LambdaQueryWrapper<RoleDataIsolationEntity> roleWrapper = baseWrapper.clone();
            roleWrapper.in(RoleDataIsolationEntity::getRoleId, roleIds);
            List<RoleDataIsolationEntity> rolePermissions = roleDataIsolationService.list(roleWrapper);
            log.debug("查询到角色权限 {} 条", rolePermissions.size());
            allPermissions.addAll(rolePermissions);
        }

        // 2. 查询用户权限（使用原生SQL查询，因为需要使用FIND_IN_SET函数）
        if (userId != null) {
            List<RoleDataIsolationEntity> userPermissions = getUserPermissions(userId);
            log.debug("查询到用户权限 {} 条", userPermissions.size());
            allPermissions.addAll(userPermissions);
        }

        // 3. 查询部门权限
        if (departmentIds != null && !departmentIds.isEmpty()) {
            List<RoleDataIsolationEntity> deptPermissions = getDepartmentPermissions(departmentIds);
            log.debug("查询到部门权限 {} 条", deptPermissions.size());
            allPermissions.addAll(deptPermissions);
        }

        log.debug("总共查询到数据权限记录数: {}", allPermissions.size());

        // 过滤有效期内的权限
        Date now = new Date();
        List<RoleDataIsolationEntity> validPermissions = allPermissions.stream()
                .filter(permission -> isPermissionValid(permission, now))
                .collect(Collectors.toList());

        log.debug("有效期内的权限记录数: {}", validPermissions.size());

        // 如果没有找到任何有效权限，返回无权限（最严格）
        if (validPermissions.isEmpty()) {
            log.debug("用户 {} 没有有效的合同数据权限", userId);
            return null; // 表示无权限
        }

        // 查找最高权限级别（ALL > DEPARTMENT > CUSTOM，我们只处理前两个）
        boolean hasAllPermission = validPermissions.stream()
                .anyMatch(p -> ContractScopeTypeEnums.ALL.equals(p.getContractScope()));

        if (hasAllPermission) {
            log.debug("用户 {} 拥有全部合同权限", userId);
            return ContractScopeTypeEnums.ALL;
        }

        boolean hasDepartmentPermission = validPermissions.stream()
                .anyMatch(p -> ContractScopeTypeEnums.DEPARTMENT.equals(p.getContractScope()));

        if (hasDepartmentPermission) {
            log.debug("用户 {} 拥有所属部门合同权限", userId);
            return ContractScopeTypeEnums.DEPARTMENT;
        }

        // 如果只有CUSTOM权限，我们暂时不处理，返回无权限
        log.debug("用户 {} 只有自定义权限或无有效权限", userId);
        return null;
    }

    /**
     * 查询用户权限（userId字段包含指定用户ID）
     *
     * @param userId 用户ID
     * @return 用户权限列表
     */
    private List<RoleDataIsolationEntity> getUserPermissions(Long userId) {
        // 查询所有启用的CONTRACT类型权限，然后在内存中过滤
        LambdaQueryWrapper<RoleDataIsolationEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RoleDataIsolationEntity::getDataType, DataType.CONTRACT)
                .eq(RoleDataIsolationEntity::getPermissionStatus, PermissionStatusType.ENABLE)
                .isNotNull(RoleDataIsolationEntity::getUserId);

        List<RoleDataIsolationEntity> allUserPermissions = roleDataIsolationService.list(wrapper);

        // 在内存中过滤包含当前用户ID的权限
        return allUserPermissions.stream()
                .filter(permission -> {
                    String userIdStr = permission.getUserId();
                    if (userIdStr == null || userIdStr.trim().isEmpty()) {
                        return false;
                    }

                    // 检查userId字段是否包含当前用户ID
                    String[] userIds = userIdStr.split(",");
                    for (String id : userIds) {
                        if (id.trim().equals(userId.toString())) {
                            return true;
                        }
                    }
                    return false;
                })
                .collect(Collectors.toList());
    }

    /**
     * 查询部门权限（departmentId字段包含指定部门ID）
     *
     * @param departmentIds 部门ID列表
     * @return 部门权限列表
     */
    private List<RoleDataIsolationEntity> getDepartmentPermissions(List<Long> departmentIds) {
        // 查询所有启用的CONTRACT类型权限，然后在内存中过滤
        LambdaQueryWrapper<RoleDataIsolationEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(RoleDataIsolationEntity::getDataType, DataType.CONTRACT)
                .eq(RoleDataIsolationEntity::getPermissionStatus, PermissionStatusType.ENABLE)
                .isNotNull(RoleDataIsolationEntity::getDepartmentId);

        List<RoleDataIsolationEntity> allDeptPermissions = roleDataIsolationService.list(wrapper);

        // 在内存中过滤包含当前用户部门ID的权限
        return allDeptPermissions.stream()
                .filter(permission -> {
                    String deptIdStr = permission.getDepartmentId();
                    if (deptIdStr == null || deptIdStr.trim().isEmpty()) {
                        return false;
                    }

                    // 检查departmentId字段是否包含当前用户的任一部门ID
                    String[] deptIds = deptIdStr.split(",");
                    for (String deptId : deptIds) {
                        String trimmedDeptId = deptId.trim();
                        for (Long userDeptId : departmentIds) {
                            if (trimmedDeptId.equals(userDeptId.toString())) {
                                return true;
                            }
                        }
                    }
                    return false;
                })
                .collect(Collectors.toList());
    }

    /**
     * 检查权限是否在有效期内
     *
     * @param permission 权限记录
     * @param now        当前时间
     * @return 是否有效
     */
    private boolean isPermissionValid(RoleDataIsolationEntity permission, Date now) {
        // 永久有效
        if (ValidityType.PERMANENT.equals(permission.getValidityType())) {
            return true;
        }

        // 固定期限
        if (ValidityType.FIXED_DATE.equals(permission.getValidityType())) {
            Date startDate = permission.getValidityStartDate();
            Date endDate = permission.getValidityEndDate();

            if (startDate != null && endDate != null) {
                return !now.before(startDate) && !now.after(endDate);
            }
        }

        return false;
    }

    /**
     * 根据权限级别应用过滤条件
     *
     * @param queryWrapper  查询包装器
     * @param userId        用户ID
     * @param departmentIds 用户部门ID列表
     * @param permission    权限级别
     */
    private void applyPermissionBasedFilter(LambdaQueryWrapper<ContractEntity> queryWrapper, Long userId,
                                            List<Long> departmentIds, ContractScopeTypeEnums permission) {
        if (permission == null) {
            // 无权限：查询不存在的记录
            queryWrapper.eq(ContractEntity::getId, -1);
            log.debug("用户 {} 无合同数据权限，返回空结果", userId);
            return;
        }

        switch (permission) {
            case ALL:
                // 全部合同：不添加额外过滤条件
                log.debug("用户 {} 拥有全部合同权限，不添加额外过滤", userId);
                break;

            case DEPARTMENT:
                // 所属部门合同：只能查看本部门的合同
                if (departmentIds != null && !departmentIds.isEmpty()) {
                    // 这里需要根据实际的合同表结构来过滤
                    // 假设合同表中有部门相关字段，或者需要通过申请人字段来关联部门
                    // 由于合同表结构复杂，我们通过申请人字段来过滤
                    log.debug("用户 {} 拥有部门合同权限，部门ID列表: {}", userId, departmentIds);
                    // 注意：这里的过滤逻辑需要在后续的动态字段过滤中实现
                    // 因为需要通过contract_field_value表来查询申请人所属部门
                } else {
                    // 用户没有部门信息，无法查看任何合同
                    queryWrapper.eq(ContractEntity::getId, -1);
                    log.debug("用户 {} 拥有部门权限但无部门信息，返回空结果", userId);
                }
                break;

            default:
                // 其他情况：无权限
                queryWrapper.eq(ContractEntity::getId, -1);
                log.debug("用户 {} 权限类型未知，返回空结果", userId);
                break;
        }
    }

    /**
     * 应用数据权限过滤到合同列表
     *
     * @param contracts 合同列表
     * @return 过滤后的合同列表
     */
    private List<ContractEntity> applyDataPermissionToContracts(List<ContractEntity> contracts) {
        ContractScopeTypeEnums permission = currentUserPermission.get();
        List<Long> userDepartmentIds = currentUserDepartments.get();

        // 如果没有权限信息，返回空列表
        if (permission == null) {
            log.debug("用户无合同数据权限，返回空列表");
            return Collections.emptyList();
        }

        // 如果是全部权限，不进行过滤
        if (ContractScopeTypeEnums.ALL.equals(permission)) {
            log.debug("用户拥有全部合同权限，不进行过滤");
            return contracts;
        }

        // 如果是部门权限，需要过滤出本部门的合同
        if (ContractScopeTypeEnums.DEPARTMENT.equals(permission)) {
            if (userDepartmentIds == null || userDepartmentIds.isEmpty()) {
                log.debug("用户拥有部门权限但无部门信息，返回空列表");
                return Collections.emptyList();
            }

            log.debug("应用部门权限过滤，用户部门ID列表: {}", userDepartmentIds);
            return filterContractsByDepartment(contracts, userDepartmentIds);
        }

        // 其他情况返回空列表
        log.debug("未知权限类型，返回空列表");
        return Collections.emptyList();
    }

    /**
     * 根据部门过滤合同（通过申请人所属部门）
     *
     * @param contracts     合同列表
     * @param departmentIds 允许的部门ID列表
     * @return 过滤后的合同列表
     */
    private List<ContractEntity> filterContractsByDepartment(List<ContractEntity> contracts, List<Long> departmentIds) {
        if (contracts.isEmpty()) {
            return contracts;
        }

        try {
            // 获取所有合同ID
            List<Integer> contractIds = contracts.stream()
                    .map(ContractEntity::getId)
                    .collect(Collectors.toList());

            // 查询所有合同的申请人ID
            // 先通过字段code查询字段ID
            Long applicantFieldId = getFieldIdByCode(SystemFieldsEnum.APPLY_PEOPLE.getCode());
            if (applicantFieldId == null) {
                log.warn("未找到申请人字段配置");
                return Collections.emptyList();
            }
            
            List<ContractFieldValueEntity> applicantFields = contractFieldValueMapper.selectList(
                    new LambdaQueryWrapper<ContractFieldValueEntity>()
                            .in(ContractFieldValueEntity::getContractId, contractIds)
                            .eq(ContractFieldValueEntity::getFieldId, applicantFieldId)
            );

            // 获取所有申请人的用户ID
            Set<Long> applicantUserIds = applicantFields.stream()
                    .map(field -> {
                        try {
                            return Long.valueOf(field.getFieldValue());
                        } catch (NumberFormatException e) {
                            log.warn("申请人字段值格式错误: {}", field.getFieldValue());
                            return null;
                        }
                    })
                    .filter(Objects::nonNull)
                    .collect(Collectors.toSet());

            if (applicantUserIds.isEmpty()) {
                log.debug("未找到有效的申请人用户ID，返回空列表");
                return Collections.emptyList();
            }

            // 查询这些用户的部门信息
            Map<Long, List<Long>> userDepartmentMap = new HashMap<>();
            for (Long userId : applicantUserIds) {
                List<Long> userDepts = sysUserDepartmentService.listDepartmentIdsByUserId(userId);
                if (userDepts != null && !userDepts.isEmpty()) {
                    userDepartmentMap.put(userId, userDepts);
                }
            }

            // 过滤出申请人属于允许部门的合同
            Set<Integer> allowedContractIds = new HashSet<>();
            for (ContractFieldValueEntity applicantField : applicantFields) {
                try {
                    Long applicantUserId = Long.valueOf(applicantField.getFieldValue());
                    List<Long> applicantDepartments = userDepartmentMap.get(applicantUserId);

                    if (applicantDepartments != null) {
                        // 检查申请人是否属于允许的部门
                        boolean hasPermission = applicantDepartments.stream()
                                .anyMatch(departmentIds::contains);

                        if (hasPermission) {
                            allowedContractIds.add(applicantField.getContractId());
                        }
                    }
                } catch (NumberFormatException e) {
                    log.warn("申请人字段值格式错误: {}", applicantField.getFieldValue());
                }
            }

            log.debug("部门权限过滤结果：总合同数 {}, 允许查看的合同数 {}", contracts.size(), allowedContractIds.size());

            // 返回过滤后的合同列表
            return contracts.stream()
                    .filter(contract -> allowedContractIds.contains(contract.getId()))
                    .collect(Collectors.toList());

        } catch (Exception e) {
            log.error("应用部门权限过滤失败", e);
            return Collections.emptyList();
        }
    }

    /**
     * 构建合同状态查询条件
     */
    private void buildContractStatusConditions(LambdaQueryWrapper<ContractEntity> queryWrapper, ContractListReqDTO request) {
        if (request.getContractStatusList() != null && !request.getContractStatusList().isEmpty()) {
            queryWrapper.in(ContractEntity::getCurrentStatus, request.getContractStatusList());
        }
    }

    /**
     * 根据动态字段条件过滤合同
     */
    private List<ContractEntity> filterByDynamicFields(List<ContractEntity> contracts, ContractListReqDTO request) {
        // 0. 首先应用数据权限过滤（仅对全部合同查询应用）
        if (request.getQueryType().getCode() == 0) {
            contracts = applyDataPermissionToContracts(contracts);
        }

        // 1. 构建完整的动态字段条件（包括根据queryType自动添加的条件）
        List<ContractListReqDTO.DynamicFieldSearchCondition> allConditions = new ArrayList<>();

        // 添加用户传入的动态字段条件
        if (request.getDynamicFieldConditions() != null) {
            allConditions.addAll(request.getDynamicFieldConditions());
        }

        // 2. 根据queryType自动添加申请人过滤条件
        if ((request.getQueryType().getCode() == 1 || request.getQueryType().getCode() == 2)
                && request.getUserId() != null) {
            // 获取申请人字段ID
            Long applicantFieldId = getFieldIdByCode(SystemFieldsEnum.APPLY_PEOPLE.getCode());
            if (applicantFieldId == null) {
                log.warn("未找到申请人字段配置，字段代码: {}", SystemFieldsEnum.APPLY_PEOPLE.getCode());
                return contracts; // 如果找不到字段配置，直接返回原合同列表
            }
            
            // 检查是否已经有申请人条件
            final Long finalApplicantFieldId = applicantFieldId;
            boolean hasApplicantCondition = allConditions.stream()
                    .anyMatch(condition -> condition.getFieldId().equals(finalApplicantFieldId));

            if (!hasApplicantCondition) {
                // 自动添加申请人字段过滤条件
                ContractListReqDTO.DynamicFieldSearchCondition applicantCondition =
                        new ContractListReqDTO.DynamicFieldSearchCondition();
                applicantCondition.setFieldId(applicantFieldId);
                applicantCondition.setFieldType("PERSON");
                applicantCondition.setValue(request.getUserId().toString());

                allConditions.add(applicantCondition);
                log.info("自动添加申请人过滤条件，userId: {}, queryType: {}",
                        request.getUserId(), request.getQueryType().getCode());
            }
        }

        // 3. 处理模糊匹配条件
        final List<Long> fuzzySearchFieldIds;
        if (request.getFuzzySearchKeyword() != null && !request.getFuzzySearchKeyword().trim().isEmpty()
                && request.getUserId() != null) {
            fuzzySearchFieldIds = getFuzzySearchFieldIds(request.getUserId(), request.getFuzzySearchFieldId());
            log.info("用户 {} 输入模糊匹配关键字: '{}', 获取到模糊匹配字段ID列表: {}",
                    request.getUserId(), request.getFuzzySearchKeyword(), fuzzySearchFieldIds);
        } else {
            fuzzySearchFieldIds = new ArrayList<>();
            if (request.getFuzzySearchKeyword() != null && !request.getFuzzySearchKeyword().trim().isEmpty()) {
                log.warn("有模糊匹配关键字 '{}' 但用户ID为空", request.getFuzzySearchKeyword());
            }
        }

        // 4. 如果没有任何动态字段条件且没有模糊匹配，直接返回
        if (allConditions.isEmpty() && fuzzySearchFieldIds.isEmpty()) {
            return contracts;
        }

        // 5. 应用动态字段过滤
        final String finalKeyword = request.getFuzzySearchKeyword();
        return contracts.stream().filter(contract -> {
            return matchesDynamicFieldConditions(contract.getId(), allConditions)
                    && matchesFuzzySearchConditions(contract.getId(), finalKeyword, fuzzySearchFieldIds);
        }).collect(Collectors.toList());
    }

    /**
     * 检查合同是否匹配动态字段条件
     */
    private boolean matchesDynamicFieldConditions(Integer contractId, List<ContractListReqDTO.DynamicFieldSearchCondition> conditions) {
        if (conditions == null || conditions.isEmpty()) {
            return true;
        }

        try {
            // 查询该合同的所有动态字段值
            List<ContractFieldValueEntity> fieldValues = contractFieldValueMapper.selectByContractId(contractId);
            log.debug("合同 {} 的动态字段值数量: {}", contractId, fieldValues.size());

            Map<Long, String> valueMap = fieldValues.stream()
                    .collect(Collectors.toMap(ContractFieldValueEntity::getFieldId, ContractFieldValueEntity::getFieldValue));

            // 检查每个搜索条件
            for (ContractListReqDTO.DynamicFieldSearchCondition condition : conditions) {
                Long fieldId = condition.getFieldId();
                String fieldValue = valueMap.get(fieldId);

                log.debug("检查合同 {} 字段 {} 的条件匹配，字段值: {}, 搜索条件: {}",
                        contractId, fieldId, fieldValue, condition.getValue());

                if (!matchesFieldCondition(fieldValue, condition)) {
                    log.debug("合同 {} 不匹配字段 {} 的条件", contractId, fieldId);
                    return false;
                }
            }
            log.debug("合同 {} 匹配所有动态字段条件", contractId);
            return true;
        } catch (Exception e) {
            log.error("检查合同 {} 的动态字段条件失败", contractId, e);
            return false;
        }
    }

    /**
     * 检查字段值是否匹配条件
     */
    private boolean matchesFieldCondition(String fieldValue, ContractListReqDTO.DynamicFieldSearchCondition condition) {
        if (fieldValue == null && condition.getValue() != null) {
            return false;
        }

        String fieldType = condition.getFieldType();
        Object conditionValue = condition.getValue();

        try {
            switch (fieldType) {
                case "NUMBER":
                case "AMOUNT":
                    // 数字类型：如果value是数组则进行范围匹配，否则进行相等匹配
                    return matchesNumberCondition(fieldValue, conditionValue);

                case "DATE":
                case "DATE_RANGE":
                    // 日期类型：如果value是数组则进行范围匹配，否则进行相等匹配
                    return matchesDateCondition(fieldValue, conditionValue);

                case "SINGLE_TEXT":
                case "MULTI_TEXT":
                    // 文本类型：进行模糊匹配
                    return matchesTextCondition(fieldValue, conditionValue);

                case "DROPDOWN_SINGLE":
                case "PERSON":
                case "DEPARTMENT":
                    // 下拉/人员/部门类型：进行精确匹配
                    return matchesDropdownCondition(fieldValue, conditionValue);

                default:
                    // 默认进行相等匹配
                    return Objects.equals(fieldValue, String.valueOf(conditionValue));
            }
        } catch (Exception e) {
            log.error("字段条件匹配失败，fieldValue: {}, condition: {}", fieldValue, condition, e);
            return false;
        }
    }

    /**
     * 数字范围匹配
     */
    private boolean matchesNumberCondition(String fieldValue, Object conditionValue) {
        if (fieldValue == null || conditionValue == null) {
            return false;
        }

        try {
            double value = Double.parseDouble(fieldValue);

            if (conditionValue instanceof List) {
                List<?> range = (List<?>) conditionValue;
                if (range.size() >= 2) {
                    double min = Double.parseDouble(String.valueOf(range.get(0)));
                    double max = Double.parseDouble(String.valueOf(range.get(1)));
                    return value >= min && value <= max;
                }
            }

            // 单值匹配
            double targetValue = Double.parseDouble(String.valueOf(conditionValue));
            return Math.abs(value - targetValue) < 0.001;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 日期范围匹配
     */
    private boolean matchesDateCondition(String fieldValue, Object conditionValue) {
        if (fieldValue == null || conditionValue == null) {
            return false;
        }

        try {
            LocalDate fieldDate = LocalDate.parse(fieldValue);

            if (conditionValue instanceof List) {
                List<?> range = (List<?>) conditionValue;
                if (range.size() >= 2) {
                    LocalDate startDate = LocalDate.parse(String.valueOf(range.get(0)));
                    LocalDate endDate = LocalDate.parse(String.valueOf(range.get(1)));
                    return !fieldDate.isBefore(startDate) && !fieldDate.isAfter(endDate);
                }
            }

            // 单值匹配
            LocalDate targetDate = LocalDate.parse(String.valueOf(conditionValue));
            return fieldDate.equals(targetDate);
        } catch (Exception e) {
            return false;
        }
    }

    /**
     * 文本模糊匹配
     */
    private boolean matchesTextCondition(String fieldValue, Object conditionValue) {
        if (fieldValue == null || conditionValue == null) {
            return false;
        }

        String searchText = String.valueOf(conditionValue).toLowerCase();
        return fieldValue.toLowerCase().contains(searchText);
    }

    /**
     * 下拉框精确匹配
     */
    private boolean matchesDropdownCondition(String fieldValue, Object conditionValue) {
        if (fieldValue == null || conditionValue == null) {
            return false;
        }

        return fieldValue.equals(String.valueOf(conditionValue));
    }

    /**
     * 获取员工表头配置中的模糊匹配字段ID列表
     *
     * @param userId             用户ID（即员工ID）
     * @param fuzzySearchFieldId 指定的模糊匹配字段ID（可选）
     * @return 可模糊匹配的字段ID列表（SINGLE_TEXT和MULTI_TEXT类型）
     */
    private List<Long> getFuzzySearchFieldIds(Long userId, Long fuzzySearchFieldId) {
        try {
            // 如果指定了模糊匹配字段ID，则验证该字段是否存在且是文本类型
            if (fuzzySearchFieldId != null) {
                ContractFieldEntity field = contractFieldMapper.selectById(fuzzySearchFieldId);
                if (field != null && ("SINGLE_TEXT".equals(field.getFieldType())
                        || "MULTI_TEXT".equals(field.getFieldType()))) {
                    log.info("使用指定的模糊匹配字段: {}", fuzzySearchFieldId);
                    return Collections.singletonList(fuzzySearchFieldId);
                } else {
                    log.warn("指定的模糊匹配字段 {} 不存在或不是文本类型，将使用默认逻辑", fuzzySearchFieldId);
                }
            }

            // 获取员工表头配置
            EmployeeTableHeaderEntity headerConfig = employeeTableHeaderService.getByEmployeeId(userId);

            List<Integer> headerFieldIds = new ArrayList<>();

            if (headerConfig == null || headerConfig.getHeaders() == null || headerConfig.getHeaders().trim().isEmpty()) {
                log.warn("员工 {} 的表头配置为空，使用默认的文本类型字段进行模糊匹配", userId);
                // 当没有表头配置时，查询所有启用的文本类型字段作为默认模糊匹配字段
                List<ContractFieldEntity> allTextFields = contractFieldMapper.selectList(
                        new LambdaQueryWrapper<ContractFieldEntity>()
                                .eq(ContractFieldEntity::getIsEnabled, true)
                                .in(ContractFieldEntity::getFieldType, Arrays.asList("SINGLE_TEXT", "MULTI_TEXT"))
                );
                return allTextFields.stream()
                        .map(ContractFieldEntity::getId)
                        .collect(Collectors.toList());
            } else {
                // 解析表头配置中的字段ID列表
                String headersStr = headerConfig.getHeaders();
                headersStr = headersStr.replace("[", "").replace("]", "");
                if (headersStr.trim().isEmpty()) {
                    log.warn("员工 {} 的表头配置为空字符串，使用默认字段", userId);
                    return new ArrayList<>();
                }

                String[] parts = headersStr.split(",");
                headerFieldIds = Arrays.stream(parts)
                        .map(String::trim)
                        .filter(s -> !s.isEmpty())
                        .map(Integer::valueOf)
                        .collect(Collectors.toList());
            }

            if (headerFieldIds.isEmpty()) {
                log.warn("员工 {} 解析后的表头字段ID列表为空", userId);
                return new ArrayList<>();
            }

            // 查询这些字段的详细信息
            List<ContractFieldEntity> fields = contractFieldMapper.selectBatchIds(headerFieldIds);
            log.info("员工 {} 的表头配置字段总数: {}, 查询到的字段数: {}", userId, headerFieldIds.size(), fields.size());

            // 筛选出SINGLE_TEXT和MULTI_TEXT类型的字段
            List<Long> textFieldIds = fields.stream()
                    .filter(field -> "SINGLE_TEXT".equals(field.getFieldType())
                            || "MULTI_TEXT".equals(field.getFieldType()))
                    .map(ContractFieldEntity::getId)
                    .collect(Collectors.toList());

            log.info("员工 {} 的可模糊匹配字段ID列表: {}", userId, textFieldIds);
            return textFieldIds;
        } catch (Exception e) {
            log.error("获取员工表头配置中的模糊匹配字段失败，userId: {}", userId, e);
            return new ArrayList<>();
        }
    }

    /**
     * 检查合同是否匹配模糊搜索条件
     *
     * @param contractId 合同ID
     * @param keyword    模糊匹配关键字
     * @param fieldIds   要检查的字段ID列表
     * @return 是否匹配
     */
    private boolean matchesFuzzySearchConditions(Integer contractId, String keyword, List<Long> fieldIds) {
        // 如果没有关键字或没有字段需要检查，则认为匹配
        if (keyword == null || keyword.trim().isEmpty()) {
            log.debug("合同 {} 没有模糊匹配关键字，跳过模糊匹配", contractId);
            return true;
        }

        if (fieldIds.isEmpty()) {
            log.debug("合同 {} 没有可模糊匹配的字段，关键字: {}", contractId, keyword);
            return false; // 有关键字但没有可搜索字段时，应该返回false
        }

        try {
            log.debug("合同 {} 模糊匹配检查，关键字: {}, 字段ID列表: {}", contractId, keyword, fieldIds);

            // 查询该合同在指定字段上的值
            List<ContractFieldValueEntity> fieldValues = contractFieldValueMapper.findValuesByContractAndFields(contractId, fieldIds);
            log.debug("合同 {} 在指定字段上的值数量: {}", contractId, fieldValues.size());

            if (fieldValues.isEmpty()) {
                log.debug("合同 {} 在指定字段上没有值，模糊匹配失败", contractId);
                return false;
            }

            String searchKeyword = keyword.toLowerCase();

            // 检查是否有任何字段值包含关键字
            boolean matches = fieldValues.stream()
                    .anyMatch(fieldValue -> {
                        if (fieldValue.getFieldValue() == null) {
                            return false;
                        }
                        boolean contains = fieldValue.getFieldValue().toLowerCase().contains(searchKeyword);
                        if (contains) {
                            log.debug("合同 {} 字段 {} 的值 '{}' 包含关键字 '{}'",
                                    contractId, fieldValue.getFieldId(), fieldValue.getFieldValue(), keyword);
                        }
                        return contains;
                    });

            log.debug("合同 {} 模糊匹配结果: {}", contractId, matches);
            return matches;
        } catch (Exception e) {
            log.error("模糊匹配检查失败，contractId: {}, keyword: {}, fieldIds: {}",
                    contractId, keyword, fieldIds, e);
            return false;
        }
    }

    private List<ContractDTO.ModuleDTO> buildModuleDTOs(Integer contractId,
                                                        List<ContractModuleEntity> modules,
                                                        Map<Integer, ContractModuleEntity> moduleMap) {
        return modules.stream().map(module -> {
            ContractDTO.ModuleDTO moduleDTO = new ContractDTO.ModuleDTO();
            BeanUtils.copyProperties(module, moduleDTO);

            // 查询模块下的所有字段
            List<ContractFieldEntity> allFields = contractModuleFieldMapper.findFieldsByModuleId(module.getId());

            // 过滤出顶级字段（只查询parentFieldId为null的字段，子字段不直接显示）
            List<ContractFieldEntity> topLevelFields = allFields.stream()
                    .filter(field -> field.getParentFieldId() == null)
                    .collect(Collectors.toList());
            List<Long> topLevelFieldIds = topLevelFields.stream().map(ContractFieldEntity::getId).collect(Collectors.toList());

            // 查询所有可能的子字段ID（包括GROUP字段的子字段）
            List<Long> allFieldIds = new ArrayList<>(topLevelFieldIds);
            for (ContractFieldEntity field : topLevelFields) {
                if ("GROUP".equals(field.getFieldType())) {
                    List<ContractFieldEntity> subFields = contractFieldMapper.findSubFieldsByParentId(field.getId());
                    allFieldIds.addAll(subFields.stream().map(ContractFieldEntity::getId).collect(Collectors.toList()));
                }
            }

            // 查询字段值（包括子字段的值）
            List<ContractFieldValueEntity> fieldValues = contractFieldValueMapper.findValuesByContractAndFields(
                    contractId, allFieldIds);
            Map<Long, String> valueMap = fieldValues.stream()
                    .collect(Collectors.toMap(ContractFieldValueEntity::getFieldId, ContractFieldValueEntity::getFieldValue));

            // 构建字段DTO（只构建顶级字段，子字段在GROUP的children中）
            moduleDTO.setFields(topLevelFields.stream()
                    .map(field -> buildFieldDTO(field, valueMap))
                    .collect(Collectors.toList()));

            return moduleDTO;
        }).collect(Collectors.toList());
    }

    private ContractDTO.ModuleDTO.FieldDTO buildFieldDTO(ContractFieldEntity field, Map<Long, String> valueMap) {
        ContractDTO.ModuleDTO.FieldDTO dto = new ContractDTO.ModuleDTO.FieldDTO();
        BeanUtils.copyProperties(field, dto);

        // 设置字段编码
        dto.setCode(field.getCode());

        // GROUP字段不存储值，子字段从valueMap中获取值
        String fieldValue = "GROUP".equals(field.getFieldType()) ? null : valueMap.get(field.getId());
        dto.setFieldValue(fieldValue);

        if (field.getFieldOptions() != null) {
            dto.setFieldOptions(JSON.parseObject(field.getFieldOptions()));
        }

        // 设置是否必填字段
        dto.setIsRequired(field.getIsRequired());

        // 处理GROUP字段的子字段
        if ("GROUP".equals(field.getFieldType())) {
            List<ContractFieldEntity> subFields = contractFieldMapper.findSubFieldsByParentId(field.getId());
            dto.setChildren(subFields.stream()
                    .map(subField -> buildFieldDTO(subField, valueMap)) // 传递valueMap给子字段
                    .collect(Collectors.toList()));
        }

        // 根据字段类型填充fieldDesc
        fillFieldDesc(dto);

        return dto;
    }

    /**
     * 根据字段类型填充fieldDesc
     */
    private void fillFieldDesc(ContractDTO.ModuleDTO.FieldDTO dto) {
        String fieldType = dto.getFieldType();
        String fieldValue = dto.getFieldValue();

        // 如果fieldValue为空，不进行处理
        if (fieldValue == null || fieldValue.trim().isEmpty()) {
            return;
        }

        try {
            switch (fieldType) {
                case "PERSON":
                    fillPersonFieldDesc(dto, fieldValue);
                    break;
                case "COUNTERPART_PEER":
                    fillCounterpartPeerFieldDesc(dto, fieldValue);
                    break;
                case "COUNTERPART_SELF":
                    fillCounterpartSelfFieldDesc(dto, fieldValue);
                    break;
                case "ATTACHMENT":
                    fillAttachmentFieldDesc(dto, fieldValue);
                    break;
                default:
                    // 其他类型不需要填充fieldDesc
                    break;
            }
        } catch (Exception e) {
            log.error("填充fieldDesc失败，fieldType: {}, fieldValue: {}", fieldType, fieldValue, e);
        }
    }

    /**
     * 填充员工类型字段的描述信息
     */
    private void fillPersonFieldDesc(ContractDTO.ModuleDTO.FieldDTO dto, String fieldValue) {
        List<Map<String, Object>> result = new ArrayList<>();

        // 解析fieldValue，可能是单个ID或ID数组
        List<Long> userIds = parseUserIds(fieldValue);

        // 批量查询用户信息
        EmployeeQueryById queryRequest = new EmployeeQueryById();
        queryRequest.setEmployeeIds(userIds);
        List<EmployeeQueryShowVO> employees = sysUserService.queryEmployeeShow(queryRequest);

        // 构建用户ID到用户信息的映射（处理重复key的情况）
        Map<Long, EmployeeQueryShowVO> userMap = employees.stream()
                .collect(Collectors.toMap(
                        EmployeeQueryShowVO::getId,
                        e -> e,
                        (existing, replacement) -> existing // 当有重复key时，保留第一个
                ));

        for (Long userId : userIds) {
            try {
                EmployeeQueryShowVO employee = userMap.get(userId);
                if (employee != null) {
                    Map<String, Object> userInfo = new HashMap<>();
                    userInfo.put("id", employee.getId());
                    userInfo.put("name", employee.getName());
                    userInfo.put("aliasName", employee.getName()); // 使用name作为aliasName
                    userInfo.put("avatar", employee.getAvatar());

                    // 获取主部门信息（使用统一的部门获取方法）
                    String departmentName = getUserDepartment(userId);
                    if (departmentName != null) {
                        // 同时需要获取部门ID，如果没有主部门就设为null
                        try {
                            SysUserDepartment mainUserDept = sysUserDepartmentService.lambdaQuery()
                                    .eq(SysUserDepartment::getUserId, userId)
                                    .eq(SysUserDepartment::getIsMain, 1)
                                    .one();

                            Long mainDeptId = null;
                            if (mainUserDept != null) {
                                mainDeptId = mainUserDept.getDepartmentId();
                            } else {
                                // 如果没有主部门，获取任意一个部门的ID
                                SysUserDepartment anyUserDept = sysUserDepartmentService.lambdaQuery()
                                        .eq(SysUserDepartment::getUserId, userId)
                                        .last("LIMIT 1")
                                        .one();
                                if (anyUserDept != null) {
                                    mainDeptId = anyUserDept.getDepartmentId();
                                }
                            }

                            userInfo.put("mainDepartmentId", mainDeptId);
                            userInfo.put("mainDepartmentName", departmentName);
                        } catch (Exception e) {
                            log.error("获取员工部门ID失败，userId: {}", userId, e);
                            userInfo.put("mainDepartmentId", null);
                            userInfo.put("mainDepartmentName", departmentName);
                        }
                    }

                    result.add(userInfo);
                } else {
                    log.warn("未找到员工信息，userId: {}", userId);
                }
            } catch (Exception e) {
                log.error("获取员工信息失败，userId: {}", userId, e);
            }
        }

        if (!result.isEmpty()) {
            dto.setFieldDesc(result);
        }
    }

    /**
     * 填充交易方（对方）字段的描述信息
     */
    private void fillCounterpartPeerFieldDesc(ContractDTO.ModuleDTO.FieldDTO dto, String fieldValue) {
        List<Map<String, Object>> result = new ArrayList<>();

        // 解析fieldValue，可能是单个ID或ID数组
        List<Integer> counterpartyIds = parseIdsFromJson(fieldValue);

        if (!counterpartyIds.isEmpty()) {
            List<CounterpartyInfoEntity> counterparties = counterpartyInfoMapper.selectByIds(counterpartyIds);
            for (CounterpartyInfoEntity counterparty : counterparties) {
                List<Integer> list = Arrays.stream(counterparty.getCounterpartyType().split(",")).map(Integer::parseInt).toList();
                Map<String, Object> info = new HashMap<>();
                info.put("id", counterparty.getId());
                info.put("counterpartyCode", counterparty.getCounterpartyCode());
                info.put("counterpartyName", counterparty.getCounterpartyName());
                info.put("registerCountry", counterparty.getRegisterCountry());
                info.put("registerCountryName", convertCountryCodeToName(counterparty.getRegisterCountry()));
                info.put("counterpartyNature", counterparty.getCounterpartyNature());
                info.put("counterpartyNatureDesc", convertCounterpartyNatureToDesc(counterparty.getCounterpartyNature()));
                info.put("counterpartyType", list);
                info.put("counterpartyTypeDesc", list.stream().map(this::convertCounterpartyTypeToDesc).toList());
                info.put("isRelatedParty", counterparty.getIsRelatedParty());
                info.put("certificateType", counterparty.getCertificateType());
                info.put("certificateTypeDesc", convertCertificateTypeToDesc(counterparty.getCertificateType()));
                info.put("certificateId", counterparty.getCertificateId());
                info.put("isEnabled", counterparty.getIsEnabled());
                info.put("createdAt", formatTimeField(counterparty.getCreatedAt()));

                // 获取银行信息
                if (counterparty.getBankInfoIds() != null && !counterparty.getBankInfoIds().isEmpty()) {
                    List<Integer> bankIds = Arrays.stream(counterparty.getBankInfoIds().split(","))
                            .map(String::trim)
                            .filter(s -> !s.isEmpty())
                            .map(Integer::parseInt)
                            .collect(Collectors.toList());

                    if (!bankIds.isEmpty()) {
                        List<BankInfoEntity> bankInfos = bankInfoMapper.selectByIds(bankIds);
                        List<BankInfoDTO> bankInfoDTOs = bankInfos.stream()
                                .map(bank -> {
                                    BankInfoDTO bankDTO = new BankInfoDTO();
                                    BeanUtils.copyProperties(bank, bankDTO);
                                    // 设置银行国家代码和名称
                                    bankDTO.setBankCountryCode(bank.getBankCountry()); // 国家代码
                                    bankDTO.setBankCountry(bank.getBankCountry()); // 国家代码
                                    bankDTO.setBankCountryName(convertCountryCodeToName(bank.getBankCountry())); // 国家名称
                                    // 设置兼容字段
                                    bankDTO.setBankAccount(bank.getAccountNumber()); // 兼容字段，值同accountNumber
                                    return bankDTO;
                                })
                                .collect(Collectors.toList());
                        info.put("bankInfoList", bankInfoDTOs);
                    }
                }

                result.add(info);
            }
        }

        if (!result.isEmpty()) {
            dto.setFieldDesc(result);
        }
    }

    /**
     * 填充法人实体（我方）字段的描述信息
     */
    private void fillCounterpartSelfFieldDesc(ContractDTO.ModuleDTO.FieldDTO dto, String fieldValue) {
        List<Map<String, Object>> result = new ArrayList<>();

        // 解析fieldValue，可能是单个ID或ID数组
        List<Integer> legalEntityIds = parseIdsFromJson(fieldValue);

        if (!legalEntityIds.isEmpty()) {
            List<LegalEntityDetailEntity> legalEntities = legalEntityDetailMapper.selectByIds(legalEntityIds);
            for (LegalEntityDetailEntity legalEntity : legalEntities) {
                Map<String, Object> info = new HashMap<>();
                info.put("id", legalEntity.getId());
                info.put("legalEntityCode", legalEntity.getLegalEntityCode());
                info.put("legalEntityName", legalEntity.getLegalEntityName());
                info.put("legalEntityAbbr", legalEntity.getLegalEntityAbbr());
                info.put("registerCountry", legalEntity.getRegisterCountry());
                info.put("detailAddress", legalEntity.getDetailAddress());
                info.put("certificateType", legalEntity.getCertificateType());
                info.put("certificateId", legalEntity.getCertificateId());
                info.put("isEnabled", legalEntity.getIsEnabled());
                info.put("statusText", legalEntity.getIsEnabled() ? "启用" : "停用");
                info.put("createdAt", formatTimeField(legalEntity.getCreatedAt()));
                info.put("updatedAt", formatTimeField(legalEntity.getUpdatedAt()));

                // 获取银行信息
                if (legalEntity.getBankInfoIds() != null && !legalEntity.getBankInfoIds().isEmpty()) {
                    List<Integer> bankIds = Arrays.stream(legalEntity.getBankInfoIds().split(","))
                            .map(String::trim)
                            .filter(s -> !s.isEmpty())
                            .map(Integer::parseInt)
                            .collect(Collectors.toList());

                    info.put("bankAccountCount", bankIds.size());

                    if (!bankIds.isEmpty()) {
                        List<BankInfoEntity> bankInfos = bankInfoMapper.selectByIds(bankIds);
                        List<BankInfoDTO> bankInfoDTOs = bankInfos.stream()
                                .map(bank -> {
                                    BankInfoDTO bankDTO = new BankInfoDTO();
                                    BeanUtils.copyProperties(bank, bankDTO);
                                    // 设置银行国家代码和名称
                                    bankDTO.setBankCountryCode(bank.getBankCountry()); // 国家代码
                                    bankDTO.setBankCountry(bank.getBankCountry()); // 国家代码
                                    bankDTO.setBankCountryName(convertCountryCodeToName(bank.getBankCountry())); // 国家名称
                                    // 设置兼容字段
                                    bankDTO.setBankAccount(bank.getAccountNumber()); // 兼容字段，值同accountNumber
                                    return bankDTO;
                                })
                                .collect(Collectors.toList());
                        info.put("bankInfoList", bankInfoDTOs);
                    }
                }

                result.add(info);
            }
        }

        if (!result.isEmpty()) {
            dto.setFieldDesc(result);
        }
    }

    /**
     * 填充附件字段的描述信息
     */
    private void fillAttachmentFieldDesc(ContractDTO.ModuleDTO.FieldDTO dto, String fieldValue) {
        List<Map<String, Object>> result = new ArrayList<>();

        // 解析fieldValue，可能是单个文件ID或文件ID数组
        List<String> fileIds = parseFileIds(fieldValue);

        for (String fileId : fileIds) {
            try {
                SingleResponse<FileVO> response = fileInfoService.getFileInfoById(fileId);
                if (response.isSuccess() && response.getData() != null) {
                    FileVO file = response.getData();
                    Map<String, Object> fileInfo = new HashMap<>();
                    fileInfo.put("fileId", file.getFileId());
                    fileInfo.put("fileName", file.getFileName());
                    fileInfo.put("fileKey", file.getFileKey());
                    fileInfo.put("fileSize", file.getFileSize());
                    fileInfo.put("fileType", file.getFileType());
                    fileInfo.put("createTime", formatTimeField(file.getCreateTime()));
                    result.add(fileInfo);
                }
            } catch (Exception e) {
                log.error("获取文件信息失败，fileId: {}", fileId, e);
            }
        }

        if (!result.isEmpty()) {
            dto.setFieldDesc(result);
        }
    }

    /**
     * 解析用户ID
     */
    private List<Long> parseUserIds(String fieldValue) {
        List<Long> userIds = new ArrayList<>();
        if (fieldValue == null || fieldValue.trim().isEmpty()) {
            return userIds;
        }

        try {
            // 尝试解析为单个ID
            userIds.add(Long.parseLong(fieldValue.trim()));
        } catch (NumberFormatException e) {
            // 尝试解析为JSON数组
            try {
                List<Integer> ids = parseIdsFromJson(fieldValue);
                userIds = ids.stream().map(Long::valueOf).collect(Collectors.toList());
            } catch (Exception ex) {
                log.error("解析用户ID失败: {}", fieldValue, ex);
            }
        }

        return userIds;
    }

    /**
     * 解析文件ID - 支持JSON数组格式
     * 输入格式示例：
     * - 单个文件：[1]
     * - 多个文件：[1,2,3]
     * - 旧格式兼容：1 或 1,2,3
     */
    private List<String> parseFileIds(String fieldValue) {
        List<String> fileIds = new ArrayList<>();
        if (fieldValue == null || fieldValue.trim().isEmpty()) {
            return fileIds;
        }

        String trimmedValue = fieldValue.trim();
        log.debug("解析文件ID，原始值: {}", trimmedValue);

        try {
            // 处理JSON数组格式：[1] 或 [1,2,3]
            if (trimmedValue.startsWith("[") && trimmedValue.endsWith("]")) {
                // 去掉方括号
                String idsStr = trimmedValue.substring(1, trimmedValue.length() - 1).trim();

                if (idsStr.isEmpty()) {
                    // 空数组 []
                    log.debug("检测到空数组，返回空列表");
                    return fileIds;
                }

                // 按逗号分割
                String[] idStrs = idsStr.split(",");
                for (String idStr : idStrs) {
                    String cleanId = idStr.trim()
                            .replaceAll("\"", "")  // 移除可能的双引号
                            .replaceAll("'", "");  // 移除可能的单引号

                    if (!cleanId.isEmpty()) {
                        fileIds.add(cleanId);
                        log.debug("解析到文件ID: {}", cleanId);
                    }
                }
            }
            // 兼容旧格式：逗号分隔 - 1,2,3
            else if (trimmedValue.contains(",")) {
                String[] idStrs = trimmedValue.split(",");
                for (String idStr : idStrs) {
                    String cleanId = idStr.trim();
                    if (!cleanId.isEmpty()) {
                        fileIds.add(cleanId);
                        log.debug("解析到文件ID（逗号分隔格式）: {}", cleanId);
                    }
                }
            }
            // 单个文件ID - 1
            else {
                fileIds.add(trimmedValue);
                log.debug("解析到单个文件ID: {}", trimmedValue);
            }
        } catch (Exception e) {
            log.error("解析文件ID失败，原始值: {}", fieldValue, e);
        }

        log.debug("文件ID解析完成，共解析到 {} 个文件ID: {}", fileIds.size(), fileIds);
        return fileIds;
    }

    /**
     * 保存或提交合同
     */
    /**
     * 将content JSON字符串中的formData转换为dynamicFields格式
     * 支持新格式{"code":"value"}和旧格式{"id":"value"}
     *
     * @param contentJson 合同表单数据JSON字符串
     * @return 转换后的动态字段Map
     */
    private Map<Long, Object> convertContentToFields(String contentJson) {
        Map<Long, Object> dynamicFields = new HashMap<>();

        if (contentJson == null || contentJson.trim().isEmpty()) {
            log.warn("convertContentToFields: contentJson为空");
            return dynamicFields;
        }

        try {
            log.info("convertContentToFields: 开始解析content JSON, 长度: {}", contentJson.length());

            // 尝试清理JSON字符串
            String cleanedJson = cleanJsonString(contentJson);
            log.info("convertContentToFields: JSON清理后长度: {}", cleanedJson.length());

            // 解析JSON字符串
            Map<String, Object> contentMap = JSON.parseObject(cleanedJson, Map.class);
            log.info("convertContentToFields: 成功解析外层JSON，keys: {}", contentMap.keySet());

            Object formDataObj = contentMap.get("formData");
            log.info("convertContentToFields: formData对象类型: {}", formDataObj != null ? formDataObj.getClass().getName() : "null");

            if (formDataObj instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, Object> formData = (Map<String, Object>) formDataObj;
                log.info("convertContentToFields: formData内容: {}", formData);

                // 收集所有需要查询的code
                List<String> codes = new ArrayList<>();
                for (String key : formData.keySet()) {
                    // 如果key不是数字，则认为是code
                    try {
                        Long.parseLong(key);
                        // 是数字，跳过（后面直接处理）
                    } catch (NumberFormatException e) {
                        // 不是数字，认为是code
                        codes.add(key);
                    }
                }

                // 批量查询code对应的字段信息
                Map<String, Long> codeToIdMap = new HashMap<>();
                if (!codes.isEmpty()) {
                    List<ContractFieldEntity> fields = contractFieldMapper.findByCodes(codes);
                    codeToIdMap = fields.stream()
                            .collect(Collectors.toMap(ContractFieldEntity::getCode, ContractFieldEntity::getId));
                    log.info("convertContentToFields: 查询到的code到ID映射: {}", codeToIdMap);
                }

                for (Map.Entry<String, Object> entry : formData.entrySet()) {
                    String key = entry.getKey();
                    Object fieldValue = entry.getValue();
                    Long fieldId = null;

                    try {
                        // 尝试解析为数字ID（兼容旧格式）
                        fieldId = Long.parseLong(key);
                        log.info("convertContentToFields: 使用ID格式 - 字段ID: {}, 值: {}", fieldId, fieldValue);
                    } catch (NumberFormatException e) {
                        // 不是数字，尝试通过code查找ID
                        fieldId = codeToIdMap.get(key);
                        if (fieldId != null) {
                            log.info("convertContentToFields: 使用code格式 - 字段code: {}, 字段ID: {}, 值: {}", key, fieldId, fieldValue);
                        } else {
                            log.warn("convertContentToFields: 未找到对应的字段ID，跳过字段: code={}, value={}", key, fieldValue);
                            continue;
                        }
                    }

                    if (fieldId != null) {
                        dynamicFields.put(fieldId, fieldValue);
                        log.info("convertContentToFields: 添加字段 - ID: {}, 值: {}", fieldId, fieldValue);
                    }
                }
            } else {
                log.warn("convertContentToFields: formData不是Map类型或为null");
            }

            log.info("转换content JSON为dynamicFields成功，转换后字段数: {}, 字段详情: {}", dynamicFields.size(), dynamicFields);

        } catch (Exception e) {
            log.error("解析content JSON失败: {}", contentJson, e);

            // 如果解析失败，尝试只提取formData部分
            try {
                log.info("尝试提取formData部分进行解析...");
                Map<Long, Object> extractedFields = extractFormDataDirectly(contentJson);
                if (!extractedFields.isEmpty()) {
                    log.info("成功通过直接提取获得 {} 个字段", extractedFields.size());
                    return extractedFields;
                }
            } catch (Exception e2) {
                log.error("直接提取formData也失败: {}", e2.getMessage());
            }
        }

        return dynamicFields;
    }

    /**
     * 清理JSON字符串，移除可能的非法字符
     */
    private String cleanJsonString(String json) {
        if (json == null) {
            return null;
        }

        // 移除可能的BOM字符和其他控制字符
        String cleaned = json.replaceAll("[\u0000-\u001F\u007F-\u009F]", "");

        // 移除可能的多余逗号（在}或]前的逗号）
        cleaned = cleaned.replaceAll(",\\s*([}\\]])", "$1");

        return cleaned.trim();
    }

    /**
     * 直接从JSON字符串中提取formData部分
     * 支持新格式{"code":"value"}和旧格式{"id":"value"}
     */
    private Map<Long, Object> extractFormDataDirectly(String contentJson) {
        Map<Long, Object> dynamicFields = new HashMap<>();

        try {
            // 查找formData的开始位置
            int formDataStart = contentJson.indexOf("\"formData\":");
            if (formDataStart == -1) {
                log.warn("未找到formData字段");
                return dynamicFields;
            }

            // 找到formData值的开始位置（{符号）
            int braceStart = contentJson.indexOf("{", formDataStart + "\"formData\":".length());
            if (braceStart == -1) {
                log.warn("未找到formData的开始大括号");
                return dynamicFields;
            }

            // 找到匹配的结束大括号
            int braceCount = 1;
            int braceEnd = braceStart + 1;
            while (braceEnd < contentJson.length() && braceCount > 0) {
                char c = contentJson.charAt(braceEnd);
                if (c == '{') {
                    braceCount++;
                } else if (c == '}') {
                    braceCount--;
                }
                braceEnd++;
            }

            if (braceCount != 0) {
                log.warn("formData的大括号不匹配");
                return dynamicFields;
            }

            // 提取formData部分
            String formDataJson = contentJson.substring(braceStart, braceEnd);
            log.info("提取到的formData JSON: {}", formDataJson);

            // 解析formData
            Map<String, Object> formData = JSON.parseObject(formDataJson, Map.class);

            // 收集所有需要查询的code
            List<String> codes = new ArrayList<>();
            for (String key : formData.keySet()) {
                // 如果key不是数字，则认为是code
                try {
                    Long.parseLong(key);
                    // 是数字，跳过（后面直接处理）
                } catch (NumberFormatException e) {
                    // 不是数字，认为是code
                    codes.add(key);
                }
            }

            // 批量查询code对应的字段信息
            Map<String, Long> codeToIdMap = new HashMap<>();
            if (!codes.isEmpty()) {
                List<ContractFieldEntity> fields = contractFieldMapper.findByCodes(codes);
                codeToIdMap = fields.stream()
                        .collect(Collectors.toMap(ContractFieldEntity::getCode, ContractFieldEntity::getId));
                log.info("extractFormDataDirectly: 查询到的code到ID映射: {}", codeToIdMap);
            }

            for (Map.Entry<String, Object> entry : formData.entrySet()) {
                String key = entry.getKey();
                Object fieldValue = entry.getValue();
                Long fieldId = null;

                try {
                    // 尝试解析为数字ID（兼容旧格式）
                    fieldId = Long.parseLong(key);
                    log.info("extractFormDataDirectly: 使用ID格式 - 字段ID: {}, 值: {}", fieldId, fieldValue);
                } catch (NumberFormatException e) {
                    // 不是数字，尝试通过code查找ID
                    fieldId = codeToIdMap.get(key);
                    if (fieldId != null) {
                        log.info("extractFormDataDirectly: 使用code格式 - 字段code: {}, 字段ID: {}, 值: {}", key, fieldId, fieldValue);
                    } else {
                        log.warn("extractFormDataDirectly: 未找到对应的字段ID，跳过字段: code={}, value={}", key, fieldValue);
                        continue;
                    }
                }

                if (fieldId != null) {
                    dynamicFields.put(fieldId, fieldValue);
                    log.info("extractFormDataDirectly: 添加字段 - ID: {}, 值: {}", fieldId, fieldValue);
                }
            }
        } catch (Exception e) {
            log.error("直接提取formData失败: {}", e.getMessage(), e);
        }

        return dynamicFields;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void submitContractForApproval(Integer contractId) {
        log.info("开始提交合同审批，合同ID: {}", contractId);

        try {
            // 1. 查询合同基础信息
            ContractEntity contract = contractMapper.selectById(contractId);
            if (contract == null) {
                throw new RuntimeException("合同不存在，合同ID: " + contractId);
            }

            // 2. 获取合同类型ID（字段ID=25）
            Integer contractTypeId = getContractTypeIdFromContract(contractId);
            if (contractTypeId == null) {
                throw new RuntimeException("合同类型未设置，无法启动审批流程");
            }
            log.info("获取到合同类型ID: {}", contractTypeId);

            // 3. 获取申请人ID（字段ID=2）
            Long applicantId = getApplicantIdFromContract(contractId);
            if (applicantId == null) {
                throw new RuntimeException("申请人未设置，无法启动审批流程");
            }
            log.info("获取到申请人ID: {}", applicantId);

            // 4. 根据合同类型查找最优流程ID（不再考虑部门）
            Long processId = findOptimalProcessIdByContractType(contractTypeId);
            if (processId == null) {
                throw new RuntimeException("未找到适合的审批流程");
            }
            log.info("找到最优流程ID: {}", processId);

            // 6. 更新合同的approval_process_id
            contract.setApprovalProcessId(processId);
            contractMapper.updateById(contract);
            log.info("更新合同审批流程ID成功");

            // 7. 启动flw审批流程
            Long instanceId = launchApprovalProcess(contract.getContent(), contractId, processId);
            log.info("启动审批流程成功，实例ID: {}", instanceId);

            // 8. 更新合同状态和实例ID
            contract.setCurrentStatus("IN_APPROVAL");
            contract.setApprovalInstanceId(instanceId);
            contractMapper.updateById(contract);

            log.info("合同审批流程启动完成，合同ID: {}, 流程ID: {}, 实例ID: {}", contractId, processId, instanceId);

            ContractNumberEvent contractNumberEvent = new ContractNumberEvent();
            contractNumberEvent.setContractId(contractId);
            contractNumberEvent.setGenerateTiming(GenerateTimingEnums.SUBMIT);
            applicationEventPublisher.publishEvent(contractNumberEvent);
            log.info("尝试为合同添加编号，查看生成时机是否为提交时");

        } catch (Exception e) {
            log.error("提交合同审批失败，合同ID: {}", contractId, e);
            throw new RuntimeException("提交合同审批失败: " + e.getMessage(), e);
        }
    }

    private Integer getContractTypeIdFromContract(Integer contractId) {
        // 先通过字段code查询字段ID
        Long contractTypeFieldId = getFieldIdByCode(SystemFieldsEnum.CONTRACT_TYPE.getCode());
        if (contractTypeFieldId == null) {
            log.warn("未找到合同类型字段配置");
            return null;
        }
        
        ContractFieldValueEntity fieldValue = contractFieldValueMapper.selectOne(
                new LambdaQueryWrapper<ContractFieldValueEntity>()
                        .eq(ContractFieldValueEntity::getContractId, contractId)
                        .eq(ContractFieldValueEntity::getFieldId, contractTypeFieldId)
        );

        if (fieldValue != null && fieldValue.getFieldValue() != null) {
            try {
                return Integer.parseInt(fieldValue.getFieldValue());
            } catch (NumberFormatException e) {
                log.error("合同类型字段值格式错误，合同ID: {}, 字段值: {}", contractId, fieldValue.getFieldValue());
                return null;
            }
        }
        return null;
    }

    private Long getApplicantIdFromContract(Integer contractId) {
        // 先通过字段code查询字段ID
        Long applicantFieldId = getFieldIdByCode(SystemFieldsEnum.APPLY_PEOPLE.getCode());
        if (applicantFieldId == null) {
            log.warn("未找到申请人字段配置");
            return null;
        }
        
        ContractFieldValueEntity fieldValue = contractFieldValueMapper.selectOne(
                new LambdaQueryWrapper<ContractFieldValueEntity>()
                        .eq(ContractFieldValueEntity::getContractId, contractId)
                        .eq(ContractFieldValueEntity::getFieldId, applicantFieldId)
        );

        if (fieldValue != null && fieldValue.getFieldValue() != null) {
            try {
                return Long.parseLong(fieldValue.getFieldValue());
            } catch (NumberFormatException e) {
                log.error("申请人字段值格式错误，合同ID: {}, 字段值: {}", contractId, fieldValue.getFieldValue());
                return null;
            }
        }
        return null;
    }

    private Long findOptimalProcessId(Integer contractTypeId, List<String> departmentIds) {
        // 根据合同类型查找工作流ID列表
        List<ContractWorkflowTypeEntity> workflowTypeList = contractWorkflowTypeMapper.selectList(
                new LambdaQueryWrapper<ContractWorkflowTypeEntity>()
                        .eq(ContractWorkflowTypeEntity::getContractTypeId, contractTypeId)
        );

        if (workflowTypeList.isEmpty()) {
            log.warn("未找到合同类型对应的工作流，合同类型ID: {}", contractTypeId);
            return null;
        }

        Set<Long> typeWorkflowIds = workflowTypeList.stream()
                .map(ContractWorkflowTypeEntity::getWorkflowId)
                .collect(Collectors.toSet());

        // 根据部门查找工作流ID列表
        List<ContractWorkflowDepartment> workflowDepartmentList = contractWorkflowDepartmentService.list(
                new LambdaQueryWrapper<ContractWorkflowDepartment>()
                        .in(ContractWorkflowDepartment::getDepartmentId, departmentIds)
        );

        Set<Long> departmentWorkflowIds = workflowDepartmentList.stream()
                .map(ContractWorkflowDepartment::getWorkflowId)
                .collect(Collectors.toSet());

        // 求交集
        typeWorkflowIds.retainAll(departmentWorkflowIds);

        if (typeWorkflowIds.isEmpty()) {
            log.warn("合同类型和部门的工作流ID交集为空，合同类型ID: {}, 部门ID列表: {}", contractTypeId, departmentIds);
            return null;
        }

        // 在交集中查找优先级最高的已发布工作流
        ContractWorkflowEntity optimalWorkflow = contractWorkflowMapper.selectOne(
                new LambdaQueryWrapper<ContractWorkflowEntity>()
                        .in(ContractWorkflowEntity::getId, typeWorkflowIds)
                        .eq(ContractWorkflowEntity::getIsEnabled, true)
                        .orderByDesc(ContractWorkflowEntity::getPriority)
                        .last("LIMIT 1")
        );

        if (optimalWorkflow == null) {
            log.warn("未找到已启用且已发布的工作流，工作流ID集合: {}", typeWorkflowIds);
            return null;
        }

        // 根据processKey查找flw_process表中版本最高的记录
        FlwProcess flwProcess = flwProcessMapper.selectOne(
                new LambdaQueryWrapper<FlwProcess>()
                        .eq(FlwProcess::getProcessKey, optimalWorkflow.getProcessKey())
                        .eq(FlwProcess::getProcessState, 1)
                        .orderByDesc(FlwProcess::getProcessVersion)
                        .last("LIMIT 1")
        );

        if (flwProcess == null) {
            log.warn("未找到对应的flw流程定义，processKey: {}", optimalWorkflow.getProcessKey());
            return null;
        }

        return flwProcess.getId();
    }

    /**
     * 根据合同类型查找最优流程ID（用于提交审批）
     * 只基于合同类型进行匹配，不考虑部门限制
     */
    private Long findOptimalProcessIdByContractType(Integer contractTypeId) {
        try {
            log.info("开始根据合同类型查找审批流程，合同类型ID: {}", contractTypeId);

            // 1. 根据合同类型查找工作流ID列表
            List<ContractWorkflowTypeEntity> workflowTypeList = contractWorkflowTypeMapper.selectList(
                    new LambdaQueryWrapper<ContractWorkflowTypeEntity>()
                            .eq(ContractWorkflowTypeEntity::getContractTypeId, contractTypeId)
            );

            if (workflowTypeList.isEmpty()) {
                log.warn("未找到合同类型对应的工作流，合同类型ID: {}", contractTypeId);
                return null;
            }

            Set<Long> typeWorkflowIds = workflowTypeList.stream()
                    .map(ContractWorkflowTypeEntity::getWorkflowId)
                    .collect(Collectors.toSet());

            log.info("找到 {} 个匹配的工作流ID: {}", typeWorkflowIds.size(), typeWorkflowIds);

            // 2. 在匹配的工作流中查找优先级最高的已启用工作流
            ContractWorkflowEntity optimalWorkflow = contractWorkflowMapper.selectOne(
                    new LambdaQueryWrapper<ContractWorkflowEntity>()
                            .in(ContractWorkflowEntity::getId, typeWorkflowIds)
                            .eq(ContractWorkflowEntity::getIsEnabled, true)
                            .orderByDesc(ContractWorkflowEntity::getPriority)
                            .last("LIMIT 1")
            );

            if (optimalWorkflow == null) {
                log.warn("未找到已启用的工作流，工作流ID集合: {}", typeWorkflowIds);
                return null;
            }

            log.info("选择的工作流: ID={}, 名称={}, 优先级={}, ProcessKey={}",
                    optimalWorkflow.getId(), optimalWorkflow.getWorkflowName(),
                    optimalWorkflow.getPriority(), optimalWorkflow.getProcessKey());

            // 3. 根据processKey查找flw_process表中版本最高的记录
            FlwProcess flwProcess = flwProcessMapper.selectOne(
                    new LambdaQueryWrapper<FlwProcess>()
                            .eq(FlwProcess::getProcessKey, optimalWorkflow.getProcessKey())
                            .eq(FlwProcess::getProcessState, 1)
                            .orderByDesc(FlwProcess::getProcessVersion)
                            .last("LIMIT 1")
            );

            if (flwProcess == null) {
                log.warn("未找到对应的flw流程定义，processKey: {}", optimalWorkflow.getProcessKey());
                return null;
            }

            log.info("成功匹配审批流程，合同类型ID: {}, 选择的流程ID: {}, 工作流ID: {}, 优先级: {}, 流程版本: {}",
                    contractTypeId, flwProcess.getId(), optimalWorkflow.getId(),
                    optimalWorkflow.getPriority(), flwProcess.getProcessVersion());

            return flwProcess.getId();

        } catch (Exception e) {
            log.error("根据合同类型查找审批流程失败，合同类型ID: {}", contractTypeId, e);
            return null;
        }
    }

    /**
     * 根据合同类型和申请人主部门查找最优流程ID（用于提交审批）
     * 只基于主部门进行匹配，确保权限控制的一致性
     * @deprecated 已废弃，改为只根据合同类型匹配流程
     */
    @Deprecated
    private Long findOptimalProcessIdForSubmit(Integer contractTypeId, Long applicantMainDepartmentId) {
        try {
            log.info("开始根据合同类型和申请人主部门查找审批流程，合同类型ID: {}, 申请人主部门ID: {}",
                    contractTypeId, applicantMainDepartmentId);

            // 1. 根据合同类型查找工作流ID列表
            List<ContractWorkflowTypeEntity> workflowTypeList = contractWorkflowTypeMapper.selectList(
                    new LambdaQueryWrapper<ContractWorkflowTypeEntity>()
                            .eq(ContractWorkflowTypeEntity::getContractTypeId, contractTypeId)
            );

            if (workflowTypeList.isEmpty()) {
                log.warn("未找到合同类型对应的工作流，合同类型ID: {}", contractTypeId);
                return null;
            }

            Set<Long> typeWorkflowIds = workflowTypeList.stream()
                    .map(ContractWorkflowTypeEntity::getWorkflowId)
                    .collect(Collectors.toSet());

            // 2. 根据申请人主部门查找工作流ID列表（只使用主部门）
            List<ContractWorkflowDepartment> workflowDepartmentList = contractWorkflowDepartmentService.list(
                    new LambdaQueryWrapper<ContractWorkflowDepartment>()
                            .eq(ContractWorkflowDepartment::getDepartmentId, applicantMainDepartmentId)
            );

            Set<Long> departmentWorkflowIds = workflowDepartmentList.stream()
                    .map(ContractWorkflowDepartment::getWorkflowId)
                    .collect(Collectors.toSet());

            // 3. 求交集（只有同时满足合同类型和主部门的工作流）
            typeWorkflowIds.retainAll(departmentWorkflowIds);

            if (typeWorkflowIds.isEmpty()) {
                log.warn("合同类型和申请人主部门的工作流ID交集为空，合同类型ID: {}, 申请人主部门ID: {}",
                        contractTypeId, applicantMainDepartmentId);
                return null;
            }

            // 4. 在交集中查找优先级最高的已发布工作流
            ContractWorkflowEntity optimalWorkflow = contractWorkflowMapper.selectOne(
                    new LambdaQueryWrapper<ContractWorkflowEntity>()
                            .in(ContractWorkflowEntity::getId, typeWorkflowIds)
                            .eq(ContractWorkflowEntity::getIsEnabled, true)
//                            .eq(ContractWorkflowEntity::getIsPublished, true)
                            .orderByDesc(ContractWorkflowEntity::getPriority)
                            .last("LIMIT 1")
            );

            if (optimalWorkflow == null) {
                log.warn("未找到已启用且已发布的工作流，工作流ID集合: {}", typeWorkflowIds);
                return null;
            }

            // 5. 根据processKey查找flw_process表中版本最高的记录
            FlwProcess flwProcess = flwProcessMapper.selectOne(
                    new LambdaQueryWrapper<FlwProcess>()
                            .eq(FlwProcess::getProcessKey, optimalWorkflow.getProcessKey())
                            .eq(FlwProcess::getProcessState, 1)
                            .orderByDesc(FlwProcess::getProcessVersion)
                            .last("LIMIT 1")
            );

            if (flwProcess == null) {
                log.warn("未找到对应的flw流程定义，processKey: {}", optimalWorkflow.getProcessKey());
                return null;
            }

            log.info("成功匹配审批流程，合同类型ID: {}, 申请人主部门ID: {}, 选择的流程ID: {}, 工作流ID: {}, 优先级: {}",
                    contractTypeId, applicantMainDepartmentId, flwProcess.getId(),
                    optimalWorkflow.getId(), optimalWorkflow.getPriority());

            return flwProcess.getId();

        } catch (Exception e) {
            log.error("根据合同类型和申请人主部门查找审批流程失败，合同类型ID: {}, 申请人主部门ID: {}",
                    contractTypeId, applicantMainDepartmentId, e);
            return null;
        }
    }

    private Long launchApprovalProcess(String content, Integer contractId, Long processId) {
        try {
            ProcessStartDTO processStartDTO = new ProcessStartDTO();
            processStartDTO.setProcessId(processId);
            processStartDTO.setSaveAsDraft(false);
            processStartDTO.setBusinessKey(contractId.toString());
            processStartDTO.setContractId(contractId);
            
            // 根据processId获取流程模型并设置未配置节点的默认处理人员
            Map<String, DynamicAssignee> assigneeMap = new HashMap<>();
            try {
                FlwProcess flwProcess = flowLongEngine.processService().getProcessById(processId);
                if (flwProcess != null) {
                    List<NodeModel> unsetAssigneeNodes = ModelHelper.getUnsetAssigneeNodes(flwProcess.model(true).getNodeConfig());
                    if (CollectionUtils.isNotEmpty(unsetAssigneeNodes)) {
                        FlowCreator currentUser = FlowHelper.getFlowCreator();
                        for (NodeModel node : unsetAssigneeNodes) {
                            // 为抄送节点和其他未设置处理人员的节点设置默认处理人员
                            NodeAssignee defaultAssignee = new NodeAssignee();
                            defaultAssignee.setId(currentUser.getCreateId());
                            defaultAssignee.setName(currentUser.getCreateBy());
                            defaultAssignee.setTenantId(currentUser.getTenantId());
                            
                            List<NodeAssignee> assigneeList = Collections.singletonList(defaultAssignee);
                            DynamicAssignee dynamicAssignee = DynamicAssignee.assigneeUserList(assigneeList);
                            assigneeMap.put(node.getNodeKey(), dynamicAssignee);
                            
                            log.info("为节点 [{}] ({}) 设置默认处理人员: {}", node.getNodeName(), node.getNodeKey(), currentUser.getCreateBy());
                        }
                    }
                }
            } catch (Exception e) {
                log.warn("设置默认处理人员时出现异常，将使用空的assigneeMap: {}", e.getMessage());
            }
            
            processStartDTO.setAssigneeMap(assigneeMap);

//            Map<String, Object> formData = new HashMap<>();
//            formData.put("contractId", contractId);
//            formData.put("processId", processId);
//
//            Map<String, Object> processFormData = new HashMap<>();
//            processFormData.put("formData", formData);
//            processFormData.put("contractId", contractId);

            processStartDTO.setProcessForm(content);

            Long instanceId = flwProcessService.launchProcess(processStartDTO, FlowHelper.getFlowCreator());

            if (instanceId == null) {
                throw new RuntimeException("启动审批流程返回的实例ID为空");
            }

            log.info("审批流程启动成功，实例ID: {}, 合同ID: {}", instanceId, contractId);
            return instanceId;
        } catch (Exception e) {
            log.error("启动flw审批流程失败，合同ID: {}, 流程ID: {}", contractId, processId, e);
            throw new RuntimeException("启动flw审批流程失败: " + e.getMessage(), e);
        }
    }

    @Override
    public ContractDTO saevAndSubmitContract(ContractAddReqDTO dto) {
        log.info("saevAndSubmitContract: 开始创建合同，操作类型: {}", dto.getOperationType());
        log.info("saevAndSubmitContract: 请求参数 - content长度: {}, basicInfo: {}",
                dto.getContent() != null ? dto.getContent().length() : 0,
                dto.getBasicInfo());

        // 0. 将content.formData转换为dynamicFields格式（兼容原有逻辑）
        Map<Long, Object> dynamicFields = convertContentToFields(dto.getContent());
        log.info("saevAndSubmitContract: 转换后的动态字段数量: {}", dynamicFields.size());

        // 1. 保存合同主表
        ContractEntity contract = buildContractEntity(dto, dynamicFields);
        contractMapper.insert(contract);

        // 2. 自动设置申请日期为当前日期
        if (dynamicFields == null) {
            dynamicFields = new HashMap<>();
        }
        autoSetApplyDate(dynamicFields);

        // 3. 保存动态字段
        log.info("saevAndSubmitContract: 准备保存动态字段，合同ID: {}, 字段数: {}", contract.getId(), dynamicFields.size());
        saveDynamicFields(dynamicFields, contract.getId());

        // 4. 如果是使用模版创建，记录模版使用情况
        // 从动态字段中获取创建方式
        String creationMethod = getCreationMethodFromDynamicFields(dynamicFields);
        // 从动态字段中获取模版ID（字段ID=238）
        Integer templateIdFromFields = getTemplateIdFromDynamicFields(dynamicFields);

        log.info("模版使用记录检查 - 创建方式: {}, 动态字段中的模版ID: {}, basicInfo中的模版ID: {}",
                creationMethod,
                templateIdFromFields,
                dto.getBasicInfo() != null ? dto.getBasicInfo().getTemplateId() : null);
        log.info("模版使用记录检查 - 所有动态字段: {}", dynamicFields);

        // 支持两种方式获取模版ID：1. 从动态字段中获取(字段ID=238) 2. 从basicInfo中获取
        Integer finalTemplateId = templateIdFromFields;
        if (finalTemplateId == null && dto.getBasicInfo() != null) {
            finalTemplateId = dto.getBasicInfo().getTemplateId();
        }

        // 支持两种创建方式判断：1. "使用模板上传" 2. "FROM_TEMPLATE"
        boolean isFromTemplate = "使用模板上传".equals(creationMethod) || "FROM_TEMPLATE".equals(creationMethod);

        if (isFromTemplate && finalTemplateId != null) {
            try {
                // 从动态字段中获取申请人ID
                Long applicantFieldId = getFieldIdByCode(SystemFieldsEnum.APPLY_PEOPLE.getCode());
                if (applicantFieldId == null) {
                    log.warn("未找到申请人字段配置，跳过模版使用记录");
                    // 找不到字段配置则跳过记录模版使用，但继续后续流程
                }
                Object applicantIdObj = dynamicFields.get(applicantFieldId);
                log.info("模版使用记录 - 申请人字段值: {}", applicantIdObj);
                if (applicantIdObj != null) {
                    String applicantId = applicantIdObj.toString();
                    log.info("开始记录模版使用 - 申请人ID: {}, 模版ID: {}", applicantId, finalTemplateId);
                    recordTemplateUsage(Long.parseLong(applicantId), finalTemplateId);
                    log.info("模版使用记录成功");
                } else {
                    log.warn("模版使用记录失败：申请人ID（字段ID=2）为空");
                }
            } catch (Exception e) {
                log.error("记录模版使用失败，但不影响合同创建", e);
            }
        } else {
            log.warn("不满足模版使用记录条件 - creationMethod: {}, isFromTemplate: {}, finalTemplateId: {}",
                    creationMethod, isFromTemplate, finalTemplateId);
        }
        //todo 提交时处理审批流程

        // 6. 将合同类型保存至最近合同类型表
        Long applicantFieldId = getFieldIdByCode(SystemFieldsEnum.APPLY_PEOPLE.getCode());
        if (applicantFieldId == null) {
            log.warn("未找到申请人字段配置，跳过最近合同类型保存");
            // 找不到字段配置则跳过最近合同类型保存，但继续后续流程
        }
        Object applicantIdObj = dynamicFields.get(applicantFieldId);
        String applicantId = null;
        if (applicantIdObj != null) {
            applicantId = applicantIdObj.toString();
            // 直接从传入的动态字段中获取合同类型ID
            Integer contractTypeId = getContractTypeIdFromRequest(dynamicFields);
            if (contractTypeId != null) {
                updateOrInsertRecentContractType(Long.parseLong(applicantId), contractTypeId);
            }
        } else {
            log.warn("无法保存最近合同类型：申请人ID（字段ID=2）为空");
        }

        // 7. 如果操作类型为NEGOTIATION，向contract_file表插入记录并创建协商实例
        if (dto.getOperationType() == ContractAddReqDTO.OperationType.NEGOTIATION) {
            try {
                // 从动态字段中获取主合同文件ID
                Long mainContractFieldId = getFieldIdByCode(SystemFieldsEnum.MAIN_CONTRACT_FILE.getCode());
                Object mainContractFileObj = null;
                if (mainContractFieldId != null) {
                    mainContractFileObj = dynamicFields.get(mainContractFieldId);
                }
                if (mainContractFileObj != null && applicantId != null) {
                    Long fileId = Long.parseLong(mainContractFileObj.toString());
                    Long currentUserId = Long.parseLong(applicantId);

                    log.info("开始创建协商合同文件记录，合同ID: {}, 文件ID: {}, 用户ID: {}",
                            contract.getId(), fileId, currentUserId);

                    // 获取文件历史版本号（可能为null，不影响正常流程）
                    Integer fileHistoryVersion = null;
                    try {
                        fileHistoryVersion = getFileHistoryVersion(fileId);
                    } catch (Exception e) {
                        log.warn("获取文件历史版本失败，但不影响主流程，文件ID: {}", fileId, e);
                    }

                    // 创建contract_file记录
                    ContractFileEntity contractFile = new ContractFileEntity()
                            .setContractId(contract.getId())
                            .setMajorVersion(1)
                            .setMinorVersion(0)
                            .setFileId(fileId)
                            .setCreateId(currentUserId)
                            .setUpdateBy(currentUserId)
                            .setCreateTime(java.time.LocalDateTime.now())
                            .setUpdateTime(java.time.LocalDateTime.now());

                    // 只有在找到有效的文件历史版本时才设置该字段
                    if (fileHistoryVersion != null) {
                        contractFile.setFileHistoryVersion(fileHistoryVersion);
                        log.info("新增合同设置文件历史版本号: {}", fileHistoryVersion);
                    } else {
                        log.info("新增合同未设置文件历史版本号（未找到有效数据），但正常创建contract_file记录");
                    }

                    // 强制保存contract_file记录，即使fileHistoryVersion为null
                    contractFileService.save(contractFile);

                    log.info("协商合同文件记录创建成功，合同ID: {}, 文件ID: {}, 版本: 1.0, 历史版本: {}",
                            contract.getId(), fileId, fileHistoryVersion);
                } else {
                    log.warn("协商合同创建时未找到主合同文件（字段ID:20），合同ID: {}", contract.getId());
                }

                // 创建协商实例记录
                createNegotiationInstance(contract.getId(), applicantId, dynamicFields);

            } catch (Exception e) {
                log.error("创建协商合同文件记录或协商实例失败，但不影响合同创建流程，合同ID: {}", contract.getId(), e);
                // 不抛出异常，避免影响合同创建流程
            }
        }

        // 8. 返回合同详情
        return getContractDetail(contract.getId());
    }

    /**
     * 记录模版使用情况
     */
    private void recordTemplateUsage(Long employeeId, Integer templateId) {
        // 1. 查询是否已有使用记录
        ContractTemplateUsageEntity usage = contractTemplateUsageMapper.selectOne(
                new LambdaQueryWrapper<ContractTemplateUsageEntity>()
                        .eq(ContractTemplateUsageEntity::getEmployeeId, employeeId)
                        .eq(ContractTemplateUsageEntity::getTemplateId, templateId)
        );

        if (usage == null) {
            // 2. 新增使用记录
            usage = new ContractTemplateUsageEntity();
            usage.setEmployeeId(employeeId);
            usage.setTemplateId(templateId);
            usage.setUsedAt(LocalDateTime.now());
            usage.setCreatedAt(LocalDateTime.now());
            contractTemplateUsageMapper.insert(usage);
        } else {
            // 3. 更新使用时间
            usage.setUsedAt(LocalDateTime.now());
            contractTemplateUsageMapper.updateById(usage);
        }
    }

    /**
     * 更新或新增员工最近使用的合同类型记录
     *
     * @param employeeId     员工ID
     * @param contractTypeId 合同类型ID
     */
    private void updateOrInsertRecentContractType(Long employeeId, Integer contractTypeId) {
        // 查询是否已存在记录
        EmployeeRecentContractTypeEntity existingRecord = employeeRecentContractTypeMapper
                .selectByEmployeeIdAndContractTypeId(employeeId, contractTypeId);

        LocalDateTime now = LocalDateTime.now();

        if (existingRecord != null) {
            // 如果存在，更新最后使用时间
            existingRecord.setLastUsedDate(now);
            existingRecord.setUpdatedAt(now);
            employeeRecentContractTypeMapper.updateById(existingRecord);
        } else {
            // 如果不存在，新增记录
            EmployeeRecentContractTypeEntity newRecord = new EmployeeRecentContractTypeEntity()
                    .setEmployeeId(employeeId)
                    .setContractTypeId(contractTypeId)
                    .setLastUsedDate(now)
                    .setCreatedAt(now)
                    .setUpdatedAt(now);
            employeeRecentContractTypeMapper.insert(newRecord);
        }
    }

    /**
     * 创建协商实例记录
     *
     * @param contractId    合同ID
     * @param applicantId   申请人ID字符串
     * @param dynamicFields 动态字段
     */
    private void createNegotiationInstance(Integer contractId, String applicantId, Map<Long, Object> dynamicFields) {
        try {
            log.info("开始创建协商实例，合同ID: {}, 申请人ID: {}", contractId, applicantId);

            if (applicantId == null) {
                log.warn("申请人ID为空，无法创建协商实例，合同ID: {}", contractId);
                return;
            }

            Long applicantIdLong = Long.parseLong(applicantId);

            // 获取合同类型ID用于选择协商配置
            Integer contractTypeId = getContractTypeIdFromRequest(dynamicFields);

            // 获取用户部门ID
            Long userDepartmentId = getUserDepartmentId(applicantIdLong);

            // 选择最优协商配置ID
            Integer configId = 1; // 默认配置ID
            try {
                Long optimalProcessId = contractNegotiationConfigService.selectOptimalNegotiationProcessId(contractTypeId, userDepartmentId);
                if (optimalProcessId != null) {
                    // 注意：这里获取的是流程ID，但我们需要的是配置ID，暂时使用默认配置ID
                    log.info("自动选择协商流程成功，合同类型ID: {}, 用户部门ID: {}, 选择的流程ID: {}, 使用默认配置ID: {}",
                            contractTypeId, userDepartmentId, optimalProcessId, configId);
                } else {
                    log.error("合同创建失败，当前合同类型未配置流程，请联系管理员配置。合同类型ID: {}", contractTypeId);
                    throw new RuntimeException("合同创建失败，当前合同类型未配置流程，请联系管理员配置");
                }
            } catch (RuntimeException e) {
                // 重新抛出RuntimeException，确保合同创建失败
                throw e;
            } catch (Exception e) {
                log.error("选择协商流程失败，合同类型ID: {}, 错误: {}", contractTypeId, e.getMessage());
                throw new RuntimeException("合同创建失败，当前合同类型未配置流程，请联系管理员配置");
            }

            // 创建协商实例
            ContractNegotiationInstanceEntity instance = new ContractNegotiationInstanceEntity()
                    .setContractId(contractId)
                    .setConfigId(configId)
                    .setNegotiationStage("发起合同申请")
                    .setNegotiationStatus("PENDING_NEGOTIATION")
                    .setStartTime(LocalDateTime.now())
                    .setApplicantId(applicantIdLong)
                    .setCreatedAt(LocalDateTime.now())
                    .setUpdatedAt(LocalDateTime.now());

            contractNegotiationInstanceMapper.insert(instance);

            log.info("协商实例创建成功，实例ID: {}, 合同ID: {}, 配置ID: {}, 申请人ID: {}",
                    instance.getId(), contractId, configId, applicantIdLong);

        } catch (Exception e) {
            log.error("创建协商实例失败，合同ID: {}, 申请人ID: {}", contractId, applicantId, e);
            // 不抛出异常，避免影响合同创建流程
        }
    }

    /**
     * 获取用户的主部门ID
     *
     * @param userId 用户ID
     * @return 用户的主部门ID，如果获取失败则返回null
     */
    private Long getUserDepartmentId(Long userId) {
        try {
            return sysUserDepartmentService.getMainDepartmentIdByUserId(userId);
        } catch (Exception e) {
            log.error("获取用户部门ID失败，用户ID: {}", userId, e);
            return null;
        }
    }

    @Override
    @Transactional
    public void updateContract(ContractUpdateReqDTO dto) {
        Integer contractId = dto.getBasicInfo().getId();

        // 0. 将content.formData转换为dynamicFields格式（兼容原有逻辑）
        Map<Long, Object> dynamicFields = convertContentToFields(dto.getContent());

        // 1. 查询合同当前状态和主合同文件ID
        ContractEntity currentContract = contractMapper.selectById(contractId);
        if (currentContract == null) {
            throw new RuntimeException("合同不存在，合同ID: " + contractId);
        }

        // 1.1 租户隔离验证已删除 - 允许修改所有合同

        // 2. 检查是否更新主合同文件且合同状态为协商中
        boolean needCreateFileVersion = false;

        // 先通过字段code查询主合同文件字段ID
        Long mainContractFileFieldId = getFieldIdByCode("main_contract_file");
        
        if ("IN_NEGOTIATION".equals(currentContract.getCurrentStatus())
                && dynamicFields != null
                && mainContractFileFieldId != null
                && dynamicFields.containsKey(mainContractFileFieldId)) {

            // 从动态字段中获取新的主合同文件ID
            Object newMainContractFileObj = dynamicFields.get(mainContractFileFieldId);
            if (newMainContractFileObj != null) {
                Long newMainContractFileId = Long.parseLong(newMainContractFileObj.toString());

                // 从动态字段中获取当前的主合同文件ID
                Long currentMainContractFileId = getCurrentMainContractFileIdFromDynamicField(contractId);

                // 比较两个文件ID是否不同
                if (!newMainContractFileId.equals(currentMainContractFileId)) {
                    needCreateFileVersion = true;
                    log.info("检测到协商中合同主文件变更，合同ID: {}, 原文件ID: {}, 新文件ID: {}",
                            contractId, currentMainContractFileId, newMainContractFileId);
                }
            }
        }

        // 3. 更新合同主表
        updateMainContract(dto, dynamicFields);

        // 4. 处理合同附件确认（字段ID为21）- 需要在更新动态字段之前执行
        if ("IN_NEGOTIATION".equals(currentContract.getCurrentStatus()) && dynamicFields != null) {
            processContractAttachmentConfirm(contractId, dynamicFields);
        }

        // 5. 处理动态字段
        if (dynamicFields != null && !dynamicFields.isEmpty()) {
            processDynamicFields(dto, dynamicFields);
        }

        // 6. 如果需要创建新的文件版本记录和操作日志
        if (needCreateFileVersion) {
            try {
                // 从动态字段中重新获取新的主合同文件ID
                Long mainContractFieldId = getFieldIdByCode(SystemFieldsEnum.MAIN_CONTRACT_FILE.getCode());
                Object newMainContractFileObj = null;
                if (mainContractFieldId != null) {
                    newMainContractFileObj = dynamicFields.get(mainContractFieldId);
                }
                if (newMainContractFileObj != null) {
                    Long newMainContractFileId = Long.parseLong(newMainContractFileObj.toString());

                    // 创建新的文件版本记录
                    createNewContractFileVersion(contractId, newMainContractFileId);

                    // 记录文件更新操作日志
                    recordFileUpdateLog(contractId, newMainContractFileId);

                    log.info("协商合同文件版本更新完成，合同ID: {}, 新文件ID: {}", contractId, newMainContractFileId);
                }
            } catch (Exception e) {
                log.error("创建文件版本记录或操作日志失败，合同ID: {}", contractId, e);
                // 不抛出异常，避免影响合同更新流程
            }
        }
    }

    @Override
    @Transactional
    public Integer copyContract(Integer contractId) {
        // 1. 查原合同
        ContractEntity originalContract = contractMapper.selectById(contractId);
        if (originalContract == null) {
            throw new RuntimeException("原合同不存在");
        }

        // 1.1 租户隔离验证已删除 - 允许复制所有合同

        // 2. 复制合同
        ContractEntity newContract = new ContractEntity();
        BeanUtils.copyProperties(originalContract, newContract);
        newContract.setId(null);
        newContract.setApprovalInstanceId(null);
        newContract.setApprovalInstanceId(null);
        newContract.setCurrentStatus("DRAFT");
        newContract.setCreatedAt(LocalDateTime.now());
        newContract.setUpdatedAt(LocalDateTime.now());
        // 确保复制的合同使用当前用户的租户键
        newContract.setSysTenantKey(originalContract.getSysTenantKey());
        contractMapper.insert(newContract);
        Integer newContractId = newContract.getId();

        // 3. 查字段值
        QueryWrapper<ContractFieldValueEntity> wrapper = new QueryWrapper<>();
        wrapper.eq("contract_id", contractId);
        List<ContractFieldValueEntity> values = contractFieldValueMapper.selectList(wrapper);

        // 4. 插入字段值
        for (ContractFieldValueEntity value : values) {
            ContractFieldValueEntity newValue = new ContractFieldValueEntity();
            BeanUtils.copyProperties(value, newValue);
            newValue.setId(null);
            newValue.setContractId(newContractId);
            newValue.setCreatedAt(new Date());
            newValue.setUpdatedAt(new Date());

            // 确保字段编码正确设置
            if (newValue.getFieldCode() == null || newValue.getFieldCode().trim().isEmpty()) {
                String fieldCode = getFieldCodeById(newValue.getFieldId());
                newValue.setFieldCode(fieldCode);
            }

            contractFieldValueMapper.insert(newValue);
        }

        return newContractId;
    }

    private void updateMainContract(ContractUpdateReqDTO dto, Map<Long, Object> dynamicFields) {
        // 检查是否有需要更新的字段
        boolean hasFieldsToUpdate = false;

        // 使用 LambdaUpdateWrapper 只更新非空字段
        LambdaUpdateWrapper<ContractEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ContractEntity::getId, dto.getBasicInfo().getId());

        if (dto.getBasicInfo().getProcessId() != null) {
            updateWrapper.set(ContractEntity::getProcessId, dto.getBasicInfo().getProcessId());
            hasFieldsToUpdate = true;
        }

        // 更新content字段
        if (dto.getContent() != null && !dto.getContent().trim().isEmpty()) {
            updateWrapper.set(ContractEntity::getContent, dto.getContent());
            hasFieldsToUpdate = true;
            log.debug("更新合同content字段，JSON字符串长度: {}", dto.getContent().length());
        }

        // 只有确实需要更新的字段存在时才执行更新，避免生成没有SET子句的SQL
        if (hasFieldsToUpdate) {
            baseMapper.update(null, updateWrapper);
            log.debug("更新合同基础信息成功，合同ID: {}", dto.getBasicInfo().getId());
        } else {
            log.debug("没有需要更新的基础字段，跳过合同基础信息更新，合同ID: {}", dto.getBasicInfo().getId());
        }
    }

    /**
     * 处理动态字段
     *
     * @param dto
     * @param dynamicFields 动态字段集合
     */
    private void processDynamicFields(ContractUpdateReqDTO dto, Map<Long, Object> dynamicFields) {
        List<ContractFieldValueEntity> fieldValues = new ArrayList<>();

        dynamicFields.forEach((fieldId, value) -> {
            // 跳过申请日期字段，申请日期在创建时设置后不应该被更新
            if (isApplyDateField(fieldId)) {
                log.info("跳过申请日期字段更新，字段ID: {}", fieldId);
                return;
            }

            // 查询字段编码
            String fieldCode = getFieldCodeById(fieldId);

            ContractFieldValueEntity entity = new ContractFieldValueEntity()
                    .setContractId(dto.getBasicInfo().getId())
                    .setFieldId(fieldId)
                    .setFieldValue(convertFieldValue(value))
                    .setFieldCode(fieldCode);
            fieldValues.add(entity);
        });

        if (!fieldValues.isEmpty()) {
            contractFieldValueMapper.batchUpsert(fieldValues);
        }
    }

    /**
     * 将动态字段的值转换为字符串
     * 支持各种数据类型的转换，包括数组类型
     *
     * @param value 动态字段的值
     * @return 转换后的字符串值
     */
    private String convertFieldValue(Object value) {
        log.debug("convertFieldValue: 开始转换值，原值: {}, 类型: {}", value, value != null ? value.getClass().getName() : "null");

        // 根据实际类型转换逻辑实现
        if (value == null) {
            log.debug("convertFieldValue: 值为null，返回null");
            return null;
        }
        if (value instanceof String) {
            log.debug("convertFieldValue: 字符串类型，直接返回: {}", value);
            return (String) value;
        }
        if (value instanceof Number) {
            String result = value.toString();
            log.debug("convertFieldValue: 数字类型，转换为字符串: {}", result);
            return result;
        }
        if (value instanceof Boolean) {
            String result = ((Boolean) value) ? "1" : "0";
            log.debug("convertFieldValue: 布尔类型，转换为: {}", result);
            return result;
        }

        // 处理日期类型，转换为年月日格式
        if (value instanceof LocalDateTime) {
            LocalDateTime dateTime = (LocalDateTime) value;
            return dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        }
        if (value instanceof Date) {
            Date date = (Date) value;
            return new java.text.SimpleDateFormat("yyyy-MM-dd").format(date);
        }

        // 处理数组/集合类型 - 转换为JSON数组格式
        if (value instanceof List) {
            List<?> list = (List<?>) value;
            if (list.isEmpty()) {
                return "[]";
            }

            // 构建JSON数组字符串
            StringBuilder sb = new StringBuilder("[");
            for (int i = 0; i < list.size(); i++) {
                if (i > 0) {
                    sb.append(",");
                }
                Object item = list.get(i);
                if (item instanceof String) {
                    // 字符串类型需要加引号（如果不是纯数字）
                    try {
                        Integer.parseInt((String) item);
                        // 如果是纯数字字符串，不加引号
                        sb.append(item);
                    } catch (NumberFormatException e) {
                        // 如果不是纯数字字符串，加引号
                        sb.append("\"").append(item).append("\"");
                    }
                } else {
                    sb.append(item);
                }
            }
            sb.append("]");
            return sb.toString();
        }

        // 处理数组类型
        if (value.getClass().isArray()) {
            // 将数组转换为List，然后递归调用
            if (value instanceof int[]) {
                List<Integer> list = Arrays.stream((int[]) value).boxed().collect(Collectors.toList());
                return convertFieldValue(list);
            } else if (value instanceof Integer[]) {
                return convertFieldValue(Arrays.asList((Integer[]) value));
            } else if (value instanceof String[]) {
                return convertFieldValue(Arrays.asList((String[]) value));
            } else {
                // 其他类型数组，转换为Object列表
                Object[] array = (Object[]) value;
                return convertFieldValue(Arrays.asList(array));
            }
        }

        return value.toString();
    }

    /**
     * 构建合同主表实体
     *
     * @param request
     * @param dynamicFields 动态字段集合
     * @return
     */
    private ContractEntity buildContractEntity(ContractAddReqDTO request, Map<Long, Object> dynamicFields) {
        ContractEntity contract = new ContractEntity();

        // 根据操作类型设置合同状态
        String status;
        switch (request.getOperationType()) {
            case SAVE:
                status = "DRAFT";
                break;
            case SUBMIT:
                status = "IN_APPROVAL";
                break;
            case NEGOTIATION:
                status = "IN_NEGOTIATION";
                break;
            default:
                status = "DRAFT";
                break;
        }

        // 基础字段映射，支持basicInfo为空的情况
        contract.setCurrentStatus(status);

        // 设置系统租户键（从员工主部门获取）
        UserInfo currentUser = AuthUtil.getCurrentUser();
        if (currentUser != null && currentUser.getEmployeeId() != null) {
            try {
                // 获取员工主部门信息
                DepartmentInfoDTO mainDepartmentInfo = sysDepartmentService.getEmployeeMainDepartmentForCompatibility(currentUser.getEmployeeId());

                if (mainDepartmentInfo != null) {
                    // 通过部门ID获取完整的部门信息以获取sys_tenant_key
                    com.aizuda.boot.modules.system.entity.SysDepartment mainDepartment = sysDepartmentService.getById(mainDepartmentInfo.getId());

                    if (mainDepartment != null && mainDepartment.getSysTenantKey() != null) {
                        contract.setSysTenantKey(mainDepartment.getSysTenantKey());
                        log.info("从员工主部门获取sys_tenant_key: {}, 部门名称: {}", mainDepartment.getSysTenantKey(), mainDepartment.getName());
                    } else {
                        // 如果无法获取主部门sys_tenant_key，则使用当前用户的作为备选
                        contract.setSysTenantKey(currentUser.getSysTenantKey());
                        log.warn("无法从员工主部门获取sys_tenant_key，使用当前用户的: {}", currentUser.getSysTenantKey());
                    }
                } else {
                    // 如果无法获取主部门信息，则使用当前用户的作为备选
                    contract.setSysTenantKey(currentUser.getSysTenantKey());
                    log.warn("无法获取员工主部门信息，使用当前用户的sys_tenant_key: {}", currentUser.getSysTenantKey());
                }
            } catch (Exception e) {
                // 异常情况下使用当前用户的sys_tenant_key作为备选
                contract.setSysTenantKey(currentUser.getSysTenantKey());
                log.error("从员工主部门获取sys_tenant_key时发生异常，使用当前用户的作为备选: {}", currentUser.getSysTenantKey(), e);
            }
        }

        if (request.getBasicInfo() != null) {
            contract.setProcessId(request.getBasicInfo().getProcessId());
        }

        // 如果workflowId为空，根据操作类getWorkflowId型和合同类型自动选择最佳工作流
        if (contract.getProcessId() == null) {
            // 从动态字段中获取合同类型ID
            Integer contractTypeId = getContractTypeIdFromRequest(dynamicFields);
            if (contractTypeId != null) {
                // 获取当前用户的部门ID（可选）
                Long userDepartmentId = getCurrentUserDepartmentId();

                Long optimalProcessId = null;

                // 根据操作类型选择不同的流程
                if (request.getOperationType() == ContractAddReqDTO.OperationType.NEGOTIATION) {
                    // 协商类型：使用协商配置的选择逻辑
                    optimalProcessId = contractNegotiationConfigService.selectOptimalNegotiationProcessId(contractTypeId, userDepartmentId);
                    if (optimalProcessId != null) {
                        contract.setProcessId(optimalProcessId);
                        log.info("自动选择协商流程成功，合同类型ID: {}, 选择的流程ID: {}（注意：不再考虑部门匹配）",
                                contractTypeId, optimalProcessId);
                    } else {
                        log.error("合同创建失败，当前合同类型未配置流程，请联系管理员配置。合同类型ID: {}", contractTypeId);
                        throw new RuntimeException("合同创建失败，当前合同类型未配置流程，请联系管理员配置");
                    }
                } else {
                    // 审批类型：使用审批工作流的选择逻辑
                    optimalProcessId = contractWorkflowService.selectOptimalWorkflowId(contractTypeId, userDepartmentId);
                    if (optimalProcessId != null) {
                        contract.setProcessId(optimalProcessId);
                        log.info("自动选择审批工作流成功，合同类型ID: {}, 选择的工作流ID: {}（注意：不再考虑部门匹配）",
                                contractTypeId, optimalProcessId);
                    } else {
                        log.warn("未找到合适的审批工作流，合同类型ID: {}, 使用默认工作流", contractTypeId);
                        contract.setProcessId(121L); // 兜底方案
                    }
                }
            } else {
                log.warn("未从动态字段中获取到合同类型ID，使用默认工作流");
                contract.setProcessId(121L); // 兜底方案
            }
        }

        // 设置content内容
        setContentFromRequest(contract, request, dynamicFields);

        return contract;
    }

    /**
     * 设置合同content内容
     *
     * @param contract      合同实体
     * @param request       创建请求
     * @param dynamicFields 动态字段集合
     */
    private void setContentFromRequest(ContractEntity contract, ContractAddReqDTO request, Map<Long, Object> dynamicFields) {
        try {
            String contentToSet = null;

            // 1. 优先使用前端传来的content JSON字符串
            if (request.getContent() != null && !request.getContent().trim().isEmpty()) {
                contentToSet = request.getContent();
                log.debug("使用前端传来的content JSON字符串，长度: {}", contentToSet.length());
            } else {
                // 2. 如果前端没有传content，且是从模版创建，则从模版获取
                String creationMethod = getCreationMethodFromDynamicFields(dynamicFields);
                boolean isFromTemplate = "使用模板上传".equals(creationMethod) || "FROM_TEMPLATE".equals(creationMethod);

                // 优先从动态字段获取模版ID，其次从basicInfo获取
                Integer templateId = getTemplateIdFromDynamicFields(dynamicFields);
                if (templateId == null && request.getBasicInfo() != null) {
                    templateId = request.getBasicInfo().getTemplateId();
                }

                if (isFromTemplate && templateId != null) {
                    // 从模版服务获取模版详情，并转换为JSON字符串
                    ContractTemplateRespDTO templateDetail = contractTemplateService.getTemplateDetail(templateId);
                    if (templateDetail != null && templateDetail.getContent() != null) {
                        // 将模版的ContractFormDataDTO转换为JSON字符串
                        contentToSet = JSON.toJSONString(templateDetail.getContent());
                        log.debug("从模版获取content并转换为JSON，模版ID: {}, content长度: {}", templateId, contentToSet.length());
                    } else {
                        log.warn("模版详情为空或content为空，模版ID: {}", templateId);
                    }
                } else {
                    log.debug("非从模版创建或无模版ID，content保持为空，创建方式: {}, 模版ID: {}", creationMethod, templateId);
                }
            }

            // 3. 设置最终的content
            contract.setContent(contentToSet);

        } catch (Exception e) {
            log.error("设置合同content失败，但不影响合同创建，错误: {}", e.getMessage(), e);
            // 不抛出异常，避免影响合同创建流程
        }
    }

    /**
     * 获取当前用户的主部门ID
     *
     * @return 当前用户的主部门ID，如果获取失败则返回null
     */
    private Long getCurrentUserDepartmentId() {
        try {
            // 从当前登录用户信息中获取
            UserSession userSession = UserSession.getLoginInfo();
            if (userSession != null && userSession.getId() != null) {
                // 获取用户的主部门ID（如果没有主部门则获取任意一个部门ID）
                Long mainDepartmentId = sysUserDepartmentService.getMainDepartmentIdByUserId(userSession.getId());
                if (mainDepartmentId != null) {
                    log.debug("获取到当前用户主部门ID: {}", mainDepartmentId);
                    return mainDepartmentId;
                } else {
                    log.warn("用户没有有效的主部门，用户ID: {}", userSession.getId());
                }
            }
            log.warn("无法获取当前用户的部门ID");
            return null;
        } catch (Exception e) {
            log.error("获取当前用户主部门ID失败", e);
            return null;
        }
    }

    /**
     * 保存动态字段
     *
     * @param dynamicFields
     * @param contractId
     */
    private void saveDynamicFields(Map<Long, Object> dynamicFields, Integer contractId) {
        log.info("saveDynamicFields: 开始保存动态字段，合同ID: {}, 字段数: {}", contractId, dynamicFields != null ? dynamicFields.size() : 0);

        if (dynamicFields == null || dynamicFields.isEmpty()) {
            log.warn("saveDynamicFields: 动态字段为空，跳过保存");
            return;
        }

        log.info("saveDynamicFields: 动态字段详情: {}", dynamicFields);

        List<ContractFieldValueEntity> values = dynamicFields.entrySet().stream()
                .map(entry -> {
                    String convertedValue = convertFieldValue(entry.getValue());
                    String fieldCode = getFieldCodeById(entry.getKey());
                    log.info("saveDynamicFields: 字段转换 - ID: {}, 原值: {}, 转换后: {}, 字段编码: {}",
                            entry.getKey(), entry.getValue(), convertedValue, fieldCode);
                    return new ContractFieldValueEntity()
                            .setContractId(contractId)
                            .setFieldId(entry.getKey())
                            .setFieldValue(convertedValue)
                            .setFieldCode(fieldCode);
                })
                .collect(Collectors.toList());

        log.info("saveDynamicFields: 准备批量插入 {} 条字段值记录", values.size());
        try {
            contractFieldValueMapper.batchInsert(values);
            log.info("saveDynamicFields: 动态字段保存成功，合同ID: {}, 插入记录数: {}", contractId, values.size());
        } catch (Exception e) {
            log.error("saveDynamicFields: 动态字段保存失败，合同ID: {}", contractId, e);
            throw e;
        }
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteDraftContracts(List<Long> contractIds) {
        if (contractIds == null || contractIds.isEmpty()) {
            return;
        }

        // 租户隔离：只删除有权限的租户下的合同
        UserInfo currentUser = AuthUtil.getCurrentUser();
        LambdaQueryWrapper<ContractEntity> queryWrapper = new LambdaQueryWrapper<ContractEntity>()
                .in(ContractEntity::getId, contractIds)
                .eq(ContractEntity::getCurrentStatus, "DRAFT");

        // 添加租户过滤
        List<String> userTenantKeys = AuthUtil.getUserTenantKeys();
        if (userTenantKeys != null && !userTenantKeys.isEmpty()) {
            queryWrapper.in(ContractEntity::getSysTenantKey, userTenantKeys);
        } else if (userTenantKeys != null) {
            // 空列表表示没有任何租户权限
            queryWrapper.eq(ContractEntity::getSysTenantKey, "NO_PERMISSION");
        }

        // 查询所有是草稿状态且属于当前租户的合同ID
        List<ContractEntity> draftContracts = contractMapper.selectList(queryWrapper);

        if (draftContracts.isEmpty()) {
            return;
        }

        List<Integer> draftIds = draftContracts.stream()
                .map(ContractEntity::getId)
                .collect(Collectors.toList());

        // 删除合同字段值表中的对应数据
        contractFieldValueMapper.delete(
                new LambdaQueryWrapper<ContractFieldValueEntity>()
                        .in(ContractFieldValueEntity::getContractId, draftIds)
        );

        // 删除合同主表数据
        contractMapper.deleteBatchIds(draftIds);
    }

    public ContractDTO getContractDetail(Integer contractId) {
        // 1. 查询合同基础信息并验证租户权限
        ContractEntity contract = contractMapper.selectById(contractId);
        if (contract == null) {
            throw new RuntimeException("合同不存在");
        }

        // 2. 租户隔离验证已删除 - 允许访问所有合同详情

        // 3. 查询所有启用的模块
        List<ContractModuleEntity> modules = contractModuleMapper.selectEnabledModules();
        Map<Integer, ContractModuleEntity> moduleMap = modules.stream()
                .collect(Collectors.toMap(ContractModuleEntity::getId, m -> m));

        // 4. 构建返回结果（复用列表查询的模块构建逻辑）
        ContractDTO dto = new ContractDTO();
        BeanUtils.copyProperties(contract, dto);
        // 设置审批流程实例ID
        dto.setInstanceId(contract.getApprovalInstanceId());
        // 移除modules字段，不再需要

        // 4.1 设置content字段（直接从contract表获取）
        dto.setContent(contract.getContent());

        // 5. 设置合同类型名称列表
        dto.setContractTypeNames(getContractTypeNamesFromDynamicFields(contractId));

        // 5. 查询并设置法人实体详情和交易方详情
        setLegalEntityAndCounterpartyDetails(dto, contractId);

        // 6. 从动态字段获取主合同文件信息（字段ID=20）
        setMainContractFileInfo(dto, contractId);

        // 7. 添加字段值信息（与合同列表保持一致）
        dto.setFields(contractFieldValueMapper.getFieldValuesWithFieldInfo(contractId));

        // 7.1 单独查询并设置fieldOptions和code
        if (dto.getFields() != null && !dto.getFields().isEmpty()) {
            // 收集所有字段ID
            List<Long> fieldIds = dto.getFields().stream()
                    .map(ContractDTO.ModuleDTO.FieldDTO::getId)
                    .collect(Collectors.toList());

            // 批量查询字段信息
            List<ContractFieldEntity> fieldEntities = contractFieldMapper.selectBatchIds(fieldIds);
            Map<Long, String> fieldOptionsMap = fieldEntities.stream()
                    .filter(f -> f.getFieldOptions() != null)
                    .collect(Collectors.toMap(f -> f.getId().longValue(), ContractFieldEntity::getFieldOptions));
            Map<Long, String> fieldCodeMap = fieldEntities.stream()
                    .collect(Collectors.toMap(f -> f.getId().longValue(), f -> f.getCode() != null ? f.getCode() : ""));

            // 设置fieldOptions和code
            for (ContractDTO.ModuleDTO.FieldDTO field : dto.getFields()) {
                // 设置code字段
                String code = fieldCodeMap.get(field.getId());
                if (code != null) {
                    field.setCode(code);
                }

                // 设置fieldOptions
                String optionsJson = fieldOptionsMap.get(field.getId());
                if (optionsJson != null && !optionsJson.trim().isEmpty()) {
                    try {
                        Map<String, Object> optionsMap = JSON.parseObject(optionsJson);
                        field.setFieldOptions(optionsMap);
                        log.debug("设置fieldOptions - 字段ID: {}, 字段名: {}, code: {}, options: {}",
                                field.getId(), field.getFieldName(), field.getCode(), optionsMap);
                    } catch (Exception e) {
                        log.error("解析fieldOptions失败，字段ID: {}, JSON: {}", field.getId(), optionsJson, e);
                    }
                }
            }
        }

        // 8. 处理字段值和字段描述（与合同列表保持一致）
        processFieldValuesAndDescriptions(dto);

        // 9. 获取并设置平铺字段
        setFlattenedFields(dto, contractId);

        return dto;
    }

    /**
     * 设置平铺的字段（从动态字段中提取）
     */
    private void setFlattenedFields(ContractDTO dto, Integer contractId) {
        // 查询合同的所有字段值
        List<ContractFieldValueEntity> fieldValues = contractFieldValueMapper.selectByContractId(contractId);

        for (ContractFieldValueEntity fieldValue : fieldValues) {
            if (fieldValue.getFieldId() == null || fieldValue.getFieldValue() == null) {
                continue;
            }

            Long fieldId = fieldValue.getFieldId();
            String value = fieldValue.getFieldValue();

            // 合同名称
            Long contractNameFieldId = getFieldIdByCode(SystemFieldsEnum.CONTRACT_NAME.getCode());
            if (contractNameFieldId != null && fieldId.equals(contractNameFieldId)) {
                dto.setContractName(value);
            }
            // 合同编号
            else {
                Long contractNumberFieldId = getFieldIdByCode(SystemFieldsEnum.CONTRACT_NUMBER.getCode());
                if (contractNumberFieldId != null && fieldId.equals(contractNumberFieldId)) {
                    dto.setContractCode(value);
                }
                // 申请日期
                else {
                    Long applyDateFieldId = getFieldIdByCode(SystemFieldsEnum.APPLY_DATE.getCode());
                    if (applyDateFieldId != null && fieldId.equals(applyDateFieldId)) {
                        try {
                            LocalDateTime applyDateTime;

                            // 检查是否包含时间部分
                            if (value.contains(" ")) {
                                // 如果包含空格，说明是 yyyy-MM-dd HH:mm:ss 格式
                                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
                                applyDateTime = LocalDateTime.parse(value, formatter);
                            } else if (value.contains("T")) {
                                // 如果包含 T，说明是 ISO 格式
                                applyDateTime = LocalDateTime.parse(value);
                            } else {
                                // 如果只是日期格式 yyyy-MM-dd，添加默认时间
                                applyDateTime = LocalDateTime.parse(value + "T00:00:00");
                            }

                            dto.setApplyDate(applyDateTime);
                        } catch (Exception e) {
                            log.error("申请日期解析失败: {}", value, e);
                        }
                    }
                    // 申请人
                    else {
                        Long applicantFieldId = getFieldIdByCode(SystemFieldsEnum.APPLY_PEOPLE.getCode());
                        if (applicantFieldId != null && fieldId.equals(applicantFieldId)) {
                            try {
                                Long applicantId = Long.parseLong(value);
                                // 获取申请人详细信息
                                EmployeeQueryById queryRequest = new EmployeeQueryById();
                                queryRequest.setEmployeeIds(Collections.singletonList(applicantId));
                                List<EmployeeQueryShowVO> employees = sysUserService.queryEmployeeShow(queryRequest);

                                if (!employees.isEmpty()) {
                                    EmployeeQueryShowVO employee = employees.get(0);
                                    dto.setApplicantName(employee.getName());
                                    dto.setApplicantNickname(employee.getName()); // 使用name作为昵称
                                    dto.setApplicantAvatar(employee.getAvatar());

                                    // 获取申请人部门信息（优先主部门，无租户隔离）
                                    String applicantDepartment = getUserDepartment(applicantId);
                                    dto.setApplicantDepartment(applicantDepartment);
                                }
                            } catch (NumberFormatException e) {
                                log.error("申请人ID格式错误: {}", value, e);
                            }
                        }
                        // 合同经办人
                        else {
                            Long handlerFieldId = getFieldIdByCode(SystemFieldsEnum.CONTRACT_HANDLER.getCode());
                            if (handlerFieldId != null && fieldId.equals(handlerFieldId)) {
                                try {
                                    Long handlerId = Long.parseLong(value);
                                    dto.setHandlerId(handlerId);

                                    // 获取经办人详细信息
                                    EmployeeQueryById queryRequest = new EmployeeQueryById();
                                    queryRequest.setEmployeeIds(Collections.singletonList(handlerId));
                                    List<EmployeeQueryShowVO> employees = sysUserService.queryEmployeeShow(queryRequest);

                                    if (!employees.isEmpty()) {
                                        EmployeeQueryShowVO employee = employees.get(0);
                                        dto.setHandlerName(employee.getName());

                                        // 获取经办人部门信息（优先主部门，无租户隔离）
                                        String handlerDepartment = getUserDepartment(handlerId);
                                        dto.setHandlerDepartment(handlerDepartment);
                                    }
                                } catch (NumberFormatException e) {
                                    log.error("经办人ID格式错误: {}", value, e);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 设置主合同文件信息
     *
     * @param dto        合同DTO
     * @param contractId 合同ID
     */
    private void setMainContractFileInfo(ContractDTO dto, Integer contractId) {
        try {
            // 从动态字段获取主合同文件ID（使用fieldCode查询）
            ContractFieldValueEntity fieldValue = contractFieldValueMapper.selectOne(
                    new LambdaQueryWrapper<ContractFieldValueEntity>()
                            .eq(ContractFieldValueEntity::getContractId, contractId)
                            .eq(ContractFieldValueEntity::getFieldCode, SystemFieldsEnum.MAIN_CONTRACT_FILE.getCode()) // 主合同文件字段code
            );

            if (fieldValue != null && fieldValue.getFieldValue() != null) {
                String fileIdStr = fieldValue.getFieldValue();

                // 查询文件信息
                SingleResponse<FileVO> fileResult = fileInfoService.getFileInfoById(fileIdStr);
                if (fileResult.isSuccess() && fileResult.getData() != null) {
                    FileVO fileInfo = fileResult.getData();
                    dto.setMainContractFileUrl(fileInfo.getFileKey());
                    dto.setMainContractFileName(fileInfo.getFileName());

                    // 设置mainContractFileId（转换为Integer类型以保持兼容性）
                    try {
                        dto.setMainContractFileId(Integer.valueOf(fileIdStr));
                    } catch (NumberFormatException e) {
                        log.warn("主合同文件ID转换为Integer失败: {}", fileIdStr, e);
                        dto.setMainContractFileId(null);
                    }
                } else {
                    log.warn("获取主合同文件信息失败，合同ID: {}, 文件ID: {}", contractId, fileIdStr);
                }
            } else {
                log.debug("合同未设置主合同文件，合同ID: {}", contractId);
            }
        } catch (Exception e) {
            log.error("设置主合同文件信息失败，合同ID: {}", contractId, e);
        }
    }


    /**
     * 设置法人实体详情列表和交易方详情列表
     */
    private void setLegalEntityAndCounterpartyDetails(ContractDTO dto, Integer contractId) {
        // 查询合同的字段值
        List<ContractFieldValueEntity> fieldValues = contractFieldValueMapper.selectByContractId(contractId);

        for (ContractFieldValueEntity fieldValue : fieldValues) {
            // 处理对方字段（使用fieldCode查询）
            if (fieldValue.getFieldCode() != null && fieldValue.getFieldCode().equals(SystemFieldsEnum.OPPOSITE.getCode()) && fieldValue.getFieldValue() != null) {
                try {
                    List<CounterpartyDetailDTO> counterpartyDetails = parseCounterpartyIds(fieldValue.getFieldValue());
                    dto.setCounterpartyDetails(counterpartyDetails);
                } catch (Exception e) {
                    log.error("解析交易方ID数组失败: {}", fieldValue.getFieldValue(), e);
                    dto.setCounterpartyDetails(new ArrayList<>());
                }
            }

            // 处理我方字段（使用fieldCode查询）
            if (fieldValue.getFieldCode() != null && fieldValue.getFieldCode().equals(SystemFieldsEnum.OUR.getCode()) && fieldValue.getFieldValue() != null) {
                try {
                    List<LegalEntityDetailDTO> legalEntityDetails = parseLegalEntityIds(fieldValue.getFieldValue());
                    dto.setLegalEntityDetails(legalEntityDetails);
                } catch (Exception e) {
                    log.error("解析法人实体ID数组失败: {}", fieldValue.getFieldValue(), e);
                    dto.setLegalEntityDetails(new ArrayList<>());
                }
            }
        }

        // 如果没有找到对应字段，设置空列表
        if (dto.getCounterpartyDetails() == null) {
            dto.setCounterpartyDetails(new ArrayList<>());
        }
        if (dto.getLegalEntityDetails() == null) {
            dto.setLegalEntityDetails(new ArrayList<>());
        }
    }

    /**
     * 解析交易方ID数组并获取详情列表
     */
    private List<CounterpartyDetailDTO> parseCounterpartyIds(String fieldValue) {
        List<CounterpartyDetailDTO> result = new ArrayList<>();

        try {
            // 尝试解析为JSON数组
            List<Integer> counterpartyIds = parseIdsFromJson(fieldValue);

            if (!counterpartyIds.isEmpty()) {
                List<CounterpartyInfoEntity> counterparties = counterpartyInfoMapper.selectByIds(counterpartyIds);
                for (CounterpartyInfoEntity counterparty : counterparties) {
                    CounterpartyDetailDTO detailDTO = new CounterpartyDetailDTO();
                    BeanUtils.copyProperties(counterparty, detailDTO);

                    // 设置枚举描述字段
                    detailDTO.setCounterpartyNatureDesc(convertCounterpartyNatureToDesc(counterparty.getCounterpartyNature()));
                    List<String> list = Arrays.stream(counterparty.getCounterpartyType().split(",")).map(Integer::parseInt).map(this::convertCounterpartyTypeToDesc).toList();
                    detailDTO.setCounterpartyTypeDesc(list);
                    detailDTO.setCertificateTypeDesc(convertCertificateTypeToDesc(counterparty.getCertificateType()));

                    // 设置国家名称
                    detailDTO.setRegisterCountryName(convertCountryCodeToName(counterparty.getRegisterCountry()));

                    // 获取银行信息
                    if (counterparty.getBankInfoIds() != null && !counterparty.getBankInfoIds().isEmpty()) {
                        List<Integer> bankIds = Arrays.stream(counterparty.getBankInfoIds().split(","))
                                .map(String::trim)
                                .filter(s -> !s.isEmpty())
                                .map(Integer::parseInt)
                                .collect(Collectors.toList());

                        if (!bankIds.isEmpty()) {
                            List<BankInfoEntity> bankInfos = bankInfoMapper.selectByIds(bankIds);
                            List<BankInfoDTO> bankInfoDTOs = bankInfos.stream()
                                    .map(bank -> {
                                        BankInfoDTO bankDTO = new BankInfoDTO();
                                        BeanUtils.copyProperties(bank, bankDTO);
                                        // 设置银行国家代码和名称
                                        bankDTO.setBankCountryCode(bank.getBankCountry()); // 国家代码
                                        bankDTO.setBankCountry(bank.getBankCountry()); // 国家代码
                                        bankDTO.setBankCountryName(convertCountryCodeToName(bank.getBankCountry())); // 国家名称
                                        // 设置兼容字段
                                        bankDTO.setBankAccount(bank.getAccountNumber()); // 兼容字段，值同accountNumber
                                        return bankDTO;
                                    })
                                    .collect(Collectors.toList());
                            detailDTO.setBankInfoList(bankInfoDTOs);
                        }
                    }

                    result.add(detailDTO);
                }
            }
        } catch (Exception e) {
            log.error("解析交易方ID数组失败: {}", fieldValue, e);
        }

        return result;
    }

    /**
     * 解析法人实体ID数组并获取详情列表
     */
    private List<LegalEntityDetailDTO> parseLegalEntityIds(String fieldValue) {
        List<LegalEntityDetailDTO> result = new ArrayList<>();

        try {
            // 尝试解析为JSON数组
            List<Integer> legalEntityIds = parseIdsFromJson(fieldValue);

            if (!legalEntityIds.isEmpty()) {
                List<LegalEntityDetailEntity> legalEntities = legalEntityDetailMapper.selectByIds(legalEntityIds);
                for (LegalEntityDetailEntity legalEntity : legalEntities) {
                    LegalEntityDetailDTO detailDTO = new LegalEntityDetailDTO();
                    BeanUtils.copyProperties(legalEntity, detailDTO);

                    // 获取银行信息
                    if (legalEntity.getBankInfoIds() != null && !legalEntity.getBankInfoIds().isEmpty()) {
                        List<Integer> bankIds = Arrays.stream(legalEntity.getBankInfoIds().split(","))
                                .map(String::trim)
                                .filter(s -> !s.isEmpty())
                                .map(Integer::parseInt)
                                .collect(Collectors.toList());

                        if (!bankIds.isEmpty()) {
                            List<BankInfoEntity> bankInfos = bankInfoMapper.selectByIds(bankIds);
                            List<BankInfoDTO> bankInfoDTOs = bankInfos.stream()
                                    .map(bank -> {
                                        BankInfoDTO bankDTO = new BankInfoDTO();
                                        BeanUtils.copyProperties(bank, bankDTO);
                                        // 设置银行国家代码和名称
                                        bankDTO.setBankCountryCode(bank.getBankCountry()); // 国家代码
                                        bankDTO.setBankCountry(bank.getBankCountry()); // 国家代码
                                        bankDTO.setBankCountryName(convertCountryCodeToName(bank.getBankCountry())); // 国家名称
                                        // 设置兼容字段
                                        bankDTO.setBankAccount(bank.getAccountNumber()); // 兼容字段，值同accountNumber
                                        return bankDTO;
                                    })
                                    .collect(Collectors.toList());
                            detailDTO.setBankInfoList(bankInfoDTOs);
                        }
                    }

                    result.add(detailDTO);
                }
            }
        } catch (Exception e) {
            log.error("解析法人实体ID数组失败: {}", fieldValue, e);
        }

        return result;
    }

    /**
     * 从JSON字符串中解析ID数组
     * 支持以下格式：
     * 1. JSON数组格式: "[1,2,3]"
     * 2. 逗号分隔格式: "1,2,3"
     * 3. 单个数字: "1"
     */
    private List<Integer> parseIdsFromJson(String fieldValue) {
        List<Integer> ids = new ArrayList<>();

        if (fieldValue == null || fieldValue.trim().isEmpty()) {
            return ids;
        }
        String trimmedValue = fieldValue.trim();
        try {
            // 如果是JSON数组格式
            if (trimmedValue.startsWith("[") && trimmedValue.endsWith("]")) {
                // 简单解析JSON数组，去掉方括号并按逗号分割
                String idsStr = trimmedValue.substring(1, trimmedValue.length() - 1);
                if (!idsStr.isEmpty()) {
                    String[] idStrs = idsStr.split(",");
                    for (String idStr : idStrs) {
                        String cleanId = idStr.trim().replaceAll("\"", "");
                        if (!cleanId.isEmpty()) {
                            ids.add(Integer.parseInt(cleanId));
                        }
                    }
                }
            }
            // 如果是逗号分隔格式
            else if (trimmedValue.contains(",")) {
                String[] idStrs = trimmedValue.split(",");
                for (String idStr : idStrs) {
                    String cleanId = idStr.trim();
                    if (!cleanId.isEmpty()) {
                        ids.add(Integer.parseInt(cleanId));
                    }
                }
            }
            // 如果是单个数字
            else {
                ids.add(Integer.parseInt(trimmedValue));
            }
        } catch (NumberFormatException e) {
            log.error("解析ID数组时发生数字格式错误: {}", fieldValue, e);
        }

        return ids;
    }

    /**
     * 从模块字段中填充外层字段信息
     *
     * @param contracts
     */
    private void fillApplicantNames(List<ContractDTO> contracts) {
        if (contracts == null || contracts.isEmpty()) {
            return;
        }

        // 收集所有需要查询的用户ID（申请人和合同经办人）
        Set<Long> userIds = new HashSet<>();

        for (ContractDTO contract : contracts) {
            if (contract.getModules() != null) {
                for (ContractDTO.ModuleDTO module : contract.getModules()) {
                    if (module.getFields() != null) {
                        for (ContractDTO.ModuleDTO.FieldDTO field : module.getFields()) {
                            // 收集申请人和合同经办人的用户ID
                            if (("申请人".equals(field.getFieldName()) || "合同经办人".equals(field.getFieldName()))
                                    && field.getFieldValue() != null && !field.getFieldValue().isEmpty()) {
                                try {
                                    userIds.add(Long.parseLong(field.getFieldValue()));
                                } catch (NumberFormatException e) {
                                    log.error("用户字段值格式错误，字段名: {}, 字段值: {}", field.getFieldName(), field.getFieldValue(), e);
                                }
                            }
                        }
                    }
                }
            }
        }

        // 批量查询用户信息
        Map<Long, EmployeeQueryShowVO> userMap = new HashMap<>();
        if (!userIds.isEmpty()) {
            EmployeeQueryById queryRequest = new EmployeeQueryById();
            queryRequest.setEmployeeIds(new ArrayList<>(userIds));
            List<EmployeeQueryShowVO> employees = sysUserService.queryEmployeeShow(queryRequest);
            userMap = employees.stream()
                    .collect(Collectors.toMap(
                            EmployeeQueryShowVO::getId,
                            e -> e,
                            (existing, replacement) -> existing // 当有重复key时，保留第一个
                    ));
        }

        // 填充外层字段信息
        for (ContractDTO contract : contracts) {
            if (contract.getModules() != null) {
                for (ContractDTO.ModuleDTO module : contract.getModules()) {
                    if (module.getFields() != null) {
                        for (ContractDTO.ModuleDTO.FieldDTO field : module.getFields()) {
                            fillExternalFieldFromModuleField(contract, field, userMap);
                        }
                    }
                }
            }
        }
    }

    /**
     * 解析日期时间字符串，支持多种格式
     *
     * @param dateTimeStr 日期时间字符串
     * @return LocalDateTime 对象，解析失败返回 null
     */
    private LocalDateTime parseDateTime(String dateTimeStr) {
        if (dateTimeStr == null || dateTimeStr.trim().isEmpty()) {
            return null;
        }

        String trimmed = dateTimeStr.trim();

        // 尝试不同的日期时间格式
        List<DateTimeFormatter> formatters = Arrays.asList(
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"),  // 2025-06-12 14:37:52
                DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss"), // 2025-06-12T14:37:52
                DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"),      // 2025-06-12 14:37
                DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm"),    // 2025-06-12T14:37
                DateTimeFormatter.ISO_LOCAL_DATE_TIME                 // ISO 标准格式
        );

        for (DateTimeFormatter formatter : formatters) {
            try {
                return LocalDateTime.parse(trimmed, formatter);
            } catch (Exception e) {
                // 继续尝试下一个格式
            }
        }

        // 如果只有日期部分，尝试解析为日期并设置时间为 00:00:00
        try {
            LocalDate date = LocalDate.parse(trimmed, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
            return date.atStartOfDay();
        } catch (Exception e) {
            // 所有格式都失败了
            log.warn("无法解析日期时间字符串: {}", dateTimeStr);
            return null;
        }
    }

    /**
     * 根据模块字段填充外层字段
     *
     * @param contract 合同DTO
     * @param field    模块字段
     * @param userMap  用户信息映射
     */
    private void fillExternalFieldFromModuleField(ContractDTO contract, ContractDTO.ModuleDTO.FieldDTO field, Map<Long, EmployeeQueryShowVO> userMap) {
        if (field.getFieldValue() == null || field.getFieldValue().isEmpty()) {
            return;
        }

        String fieldName = field.getFieldName();
        String fieldValue = field.getFieldValue();

        try {
            switch (fieldName) {
                case "申请人":
                    Long applicantId = Long.parseLong(fieldValue);
                    EmployeeQueryShowVO applicant = userMap.get(applicantId);
                    if (applicant != null) {
                        contract.setApplicantName(applicant.getAliasName());
                        contract.setApplicantNickname(applicant.getName());
                        contract.setApplicantAvatar(applicant.getAvatar());
                        // 使用统一的部门获取方法（优先主部门，无租户隔离）
                        String applicantDepartment = getUserDepartment(applicantId);
                        contract.setApplicantDepartment(applicantDepartment);
                    }
                    break;

                case "合同经办人":
                    Long handlerId = Long.parseLong(fieldValue);
                    contract.setHandlerId(handlerId);
                    EmployeeQueryShowVO handler = userMap.get(handlerId);
                    if (handler != null) {
                        contract.setHandlerName(handler.getAliasName());
                        // 使用统一的部门获取方法（优先主部门，无租户隔离）
                        String handlerDepartment = getUserDepartment(handlerId);
                        contract.setHandlerDepartment(handlerDepartment);
                    }
                    break;

                case "合同名称":
                    contract.setContractName(fieldValue);
                    break;

                case "合同编号":
                    contract.setContractCode(fieldValue);
                    break;


                case "申请日期":
                    try {
                        LocalDateTime applyDate = parseDateTime(fieldValue);
                        if (applyDate != null) {
                            contract.setApplyDate(applyDate);
                        }
                    } catch (Exception e) {
                        log.error("申请日期字段值格式错误: {}", fieldValue, e);
                    }
                    break;

                default:
                    // 对于其他字段，暂不处理
                    break;
            }
        } catch (Exception e) {
            log.error("填充外层字段失败，字段名: {}, 字段值: {}", fieldName, fieldValue, e);
        }
    }

    @Override
    public List<ContractTypeEntity> getAllContractTypesTree() {
        // 1. 获取当前用户信息进行权限过滤
        UserInfo currentUser = AuthUtil.getCurrentUser();
        if (currentUser == null || currentUser.getId() == null) {
            log.warn("无法获取当前用户信息，返回空的合同类型列表");
            return new ArrayList<>();
        }

        // 2. 初始化允许的合同类型ID集合
        Set<Integer> allowedTypeIds = new HashSet<>();

        // 3. 查询部门权限（如果用户有主部门）
        Long mainDepartmentId = sysUserDepartmentService.getMainDepartmentIdByUserId(currentUser.getId());
        if (mainDepartmentId != null) {
            List<ContractTypeDepartmentEntity> typeDepartments = contractTypeDepartmentService.list(
                    new LambdaQueryWrapper<ContractTypeDepartmentEntity>()
                            .eq(ContractTypeDepartmentEntity::getDepartmentId, mainDepartmentId)
            );
            
            // 添加部门权限的合同类型ID
            allowedTypeIds.addAll(typeDepartments.stream()
                    .map(ContractTypeDepartmentEntity::getContractTypeId)
                    .collect(Collectors.toSet()));
        }

        // 4. 查询用户个人权限
        List<ContractTypeUser> userTypes = contractTypeUserService.list(
                new LambdaQueryWrapper<ContractTypeUser>()
                        .eq(ContractTypeUser::getUserId, currentUser.getId())
        );
        
        // 添加用户个人权限的合同类型ID
        allowedTypeIds.addAll(userTypes.stream()
                .map(ContractTypeUser::getContractTypeId)
                .collect(Collectors.toSet()));

        // 5. 如果没有任何权限，返回空列表
        if (allowedTypeIds.isEmpty()) {
            log.debug("用户 {} 没有任何合同类型权限", currentUser.getId());
            return new ArrayList<>();
        }

        // 6. 查询启用的合同类型并按权限过滤
        List<ContractTypeEntity> allTypes = contractTypeMapper.selectList(
                new QueryWrapper<ContractTypeEntity>()
                        .eq("is_enabled", true)
                        .in("id", allowedTypeIds)
                        .orderByAsc("type_order")
        );

        // 7. 构建多层级树形结构
        return buildTree(allTypes, null);
    }

    /**
     * 递归构建多层级树形结构
     *
     * @param allTypes 所有类型列表
     * @param parentId 父级ID（null表示根节点）
     * @return 树形结构列表
     */
    private List<ContractTypeEntity> buildTree(List<ContractTypeEntity> allTypes, Integer parentId) {
        List<ContractTypeEntity> result = new ArrayList<>();

        for (ContractTypeEntity type : allTypes) {
            // 找到当前层级的节点
            if ((parentId == null && type.getParentId() == null) ||
                    (parentId != null && parentId.equals(type.getParentId()))) {

                // 递归查找子节点
                List<ContractTypeEntity> children = buildTree(allTypes, type.getId());
                type.setChildren(children);

                result.add(type);
            }
        }

        return result;
    }

    @Override
    public List<ContractTypeEntity> getRecentContractTypes(Long employeeId, int limit) {
        // 1. 获取最近使用的合同类型
        List<ContractTypeEntity> recentTypes = employeeRecentContractTypeMapper.findRecentContractTypes(employeeId, limit);

        // 2. 获取当前用户的主部门ID进行权限过滤
        UserInfo currentUser = AuthUtil.getCurrentUser();
        if (currentUser != null && currentUser.getId() != null) {
            Long mainDepartmentId = sysUserDepartmentService.getMainDepartmentIdByUserId(currentUser.getId());
            if (mainDepartmentId != null) {
                // 3. 过滤出当前用户主部门匹配的合同类型
                recentTypes = filterContractTypesByDepartment(recentTypes, mainDepartmentId);
            } else {
                log.warn("用户 {} 没有主部门信息，返回空的合同类型列表", currentUser.getId());
                return new ArrayList<>();
            }
        } else {
            log.warn("无法获取当前用户信息，返回空的合同类型列表");
            return new ArrayList<>();
        }

        // 4. 为每个合同类型构建完整的父类别路径
        for (ContractTypeEntity contractType : recentTypes) {
            List<String> parentNames = buildParentTypeNames(contractType.getParentId());
            contractType.setParentTypeNames(parentNames.toArray(new String[0]));
        }

        return recentTypes;
    }

    /**
     * 根据部门和用户权限过滤合同类型
     * 返回当前用户部门权限或个人权限匹配的合同类型
     *
     * @param contractTypes    合同类型列表
     * @param mainDepartmentId 用户主部门ID
     * @return 过滤后的合同类型列表
     */
    private List<ContractTypeEntity> filterContractTypesByDepartment(List<ContractTypeEntity> contractTypes, Long mainDepartmentId) {
        if (contractTypes == null || contractTypes.isEmpty()) {
            return new ArrayList<>();
        }

        // 获取当前用户信息
        UserInfo currentUser = AuthUtil.getCurrentUser();
        if (currentUser == null || currentUser.getId() == null) {
            return new ArrayList<>();
        }

        // 初始化允许的合同类型ID集合
        Set<Integer> allowedTypeIds = new HashSet<>();

        // 查询部门权限（如果用户有主部门）
        if (mainDepartmentId != null) {
            List<ContractTypeDepartmentEntity> typeDepartments = contractTypeDepartmentService.list(
                    new LambdaQueryWrapper<ContractTypeDepartmentEntity>()
                            .eq(ContractTypeDepartmentEntity::getDepartmentId, mainDepartmentId)
            );
            
            // 添加部门权限的合同类型ID
            allowedTypeIds.addAll(typeDepartments.stream()
                    .map(ContractTypeDepartmentEntity::getContractTypeId)
                    .collect(Collectors.toSet()));
        }

        // 查询用户个人权限
        List<ContractTypeUser> userTypes = contractTypeUserService.list(
                new LambdaQueryWrapper<ContractTypeUser>()
                        .eq(ContractTypeUser::getUserId, currentUser.getId())
        );
        
        // 添加用户个人权限的合同类型ID
        allowedTypeIds.addAll(userTypes.stream()
                .map(ContractTypeUser::getContractTypeId)
                .collect(Collectors.toSet()));

        // 如果没有任何权限，返回空列表
        if (allowedTypeIds.isEmpty()) {
            log.debug("用户 {} 没有任何合同类型权限", currentUser.getId());
            return new ArrayList<>();
        }

        // 过滤合同类型
        List<ContractTypeEntity> filteredTypes = contractTypes.stream()
                .filter(contractType -> allowedTypeIds.contains(contractType.getId()))
                .collect(Collectors.toList());

        log.debug("用户 {} 过滤前合同类型数量: {}, 过滤后数量: {}", currentUser.getId(), contractTypes.size(), filteredTypes.size());
        return filteredTypes;
    }

    /**
     * 递归构建父类别名称路径
     *
     * @param parentId 父类别ID
     * @return 父类别名称列表（从根类别到直接父类别）
     */
    private List<String> buildParentTypeNames(Integer parentId) {
        List<String> parentNames = new ArrayList<>();

        // 如果parentId为null，说明已经是一级类别，返回空列表
        if (parentId == null) {
            return parentNames;
        }

        // 查询父类别
        ContractTypeEntity parentType = contractTypeMapper.selectById(parentId);
        if (parentType != null) {
            // 将当前父类别名称添加到列表
            parentNames.add(parentType.getTypeName());

            // 递归查询上一级父类别
            List<String> grandParentNames = buildParentTypeNames(parentType.getParentId());

            // 将上级父类别名称添加到列表末尾
            parentNames.addAll(grandParentNames);
        }

        // 反转列表，使一级类别在第一个位置
        Collections.reverse(parentNames);
        return parentNames;
    }

    /**
     * 从动态字段中获取合同类型ID
     *
     * @param contractId 合同ID
     * @return 合同类型ID
     */
    private Integer getContractTypeIdFromDynamicFields(Integer contractId) {
        // 先通过字段code查询合同类型字段ID
        Long contractTypeFieldId = getFieldIdByCode(SystemFieldsEnum.CONTRACT_TYPE.getCode());
        if (contractTypeFieldId == null) {
            log.warn("未找到合同类型字段配置");
            return null;
        }
        
        List<ContractFieldValueEntity> fieldValues = contractFieldValueMapper.selectList(
                new LambdaQueryWrapper<ContractFieldValueEntity>()
                        .eq(ContractFieldValueEntity::getContractId, contractId)
                        .eq(ContractFieldValueEntity::getFieldId, contractTypeFieldId)
        );

        if (!fieldValues.isEmpty()) {
            ContractFieldValueEntity fieldValue = fieldValues.get(0);
            try {
                return Integer.parseInt(fieldValue.getFieldValue());
            } catch (NumberFormatException e) {
                log.error("合同类型字段值格式错误: {}", fieldValue.getFieldValue(), e);
                return null;
            }
        }
        return null;
    }

    /**
     * 获取合同类型完整名称数组（包含所有层级）
     *
     * @param contractTypeId 合同类型ID
     * @return 合同类型名称数组，从一级到当前级别
     */
    private String[] getContractTypeNamesArray(Integer contractTypeId) {
        if (contractTypeId == null) {
            return new String[0];
        }

        List<String> typeNames = new ArrayList<>();
        ContractTypeEntity currentType = contractTypeMapper.selectById(contractTypeId);

        while (currentType != null) {
            typeNames.add(0, currentType.getTypeName()); // 在列表开头插入

            if (currentType.getParentId() != null) {
                currentType = contractTypeMapper.selectById(currentType.getParentId());
            } else {
                break;
            }
        }

        return typeNames.toArray(new String[0]);
    }

    /**
     * 从动态字段中获取合同类型名称列表
     *
     * @param contractId 合同ID
     * @return 合同类型名称列表，从一级到当前级别
     */
    private List<String> getContractTypeNamesFromDynamicFields(Integer contractId) {
        Integer contractTypeId = getContractTypeIdFromDynamicFields(contractId);
        if (contractTypeId == null) {
            return new ArrayList<>();
        }

        List<String> typeNames = new ArrayList<>();
        ContractTypeEntity currentType = contractTypeMapper.selectById(contractTypeId);

        // 递归查找所有父级类型
        while (currentType != null) {
            typeNames.add(0, currentType.getTypeName()); // 在列表开头插入

            if (currentType.getParentId() != null) {
                currentType = contractTypeMapper.selectById(currentType.getParentId());
            } else {
                break;
            }
        }

        return typeNames;
    }

    /**
     * 判断是否是合同类型字段
     *
     * @param fieldId 字段ID
     * @return 是否是合同类型字段
     */
    private boolean isContractTypeField(Long fieldId) {
        // 合同类型字段
        Long contractTypeFieldId = getFieldIdByCode(SystemFieldsEnum.CONTRACT_TYPE.getCode());
        return contractTypeFieldId != null && fieldId != null && fieldId.equals(contractTypeFieldId);
    }

    /**
     * 从动态字段中获取创建方式
     *
     * @param dynamicFields 动态字段集合
     * @return 创建方式
     */
    private String getCreationMethodFromDynamicFields(Map<Long, Object> dynamicFields) {
        if (dynamicFields == null || dynamicFields.isEmpty()) {
            return null;
        }

        // 遍历动态字段，查找创建方式字段
        for (Map.Entry<Long, Object> entry : dynamicFields.entrySet()) {
            Long fieldId = entry.getKey();
            Object value = entry.getValue();

            // TODO: 这里需要根据实际的创建方式字段ID进行判断
            if (isCreationMethodField(fieldId)) {
                return value != null ? value.toString() : null;
            }
        }
        return null;
    }

    /**
     * 判断是否是创建方式字段
     *
     * @param fieldId 字段ID
     * @return 是否是创建方式字段
     */
    private boolean isCreationMethodField(Long fieldId) {
        // 创建方式字段
        Long creationMethodFieldId = getFieldIdByCode(SystemFieldsEnum.CREATE_TYPE.getCode());
        return creationMethodFieldId != null && fieldId != null && fieldId.equals(creationMethodFieldId);
    }

    private boolean isContractAttachmentField(Long fieldId) {
        // 合同附件字段
        Long contractAttachmentFieldId = getFieldIdByCode(SystemFieldsEnum.CONTRACT_ATTACHMENT.getCode());
        return contractAttachmentFieldId != null && fieldId != null && fieldId.equals(contractAttachmentFieldId);
    }

    /**
     * 从动态字段中获取模版ID
     *
     * @param dynamicFields 动态字段集合
     * @return 模版ID
     */
    private Integer getTemplateIdFromDynamicFields(Map<Long, Object> dynamicFields) {
        if (dynamicFields == null || dynamicFields.isEmpty()) {
            return null;
        }

        // 从模版ID字段获取模版ID
        Long templateFieldId = getFieldIdByCode(SystemFieldsEnum.TEMPLATE_ID.getCode());
        if (templateFieldId == null) {
            log.warn("无法获取模版ID字段ID");
            return null;
        }
        Object templateIdObj = dynamicFields.get(templateFieldId);
        if (templateIdObj != null) {
            try {
                return Integer.parseInt(templateIdObj.toString());
            } catch (NumberFormatException e) {
                log.warn("模版ID字段值格式错误，无法转换为Integer: {}", templateIdObj);
                return null;
            }
        }
        return null;
    }

    /**
     * 根据字段名称获取字段ID
     *
     * @param fieldName 字段名称
     * @return 字段ID
     */
    private Long getFieldIdByName(String fieldName) {
        // 根据字段名称映射到字段code，然后通过code查找ID
        String fieldCode = mapFieldNameToCode(fieldName);
        if (fieldCode != null) {
            return getFieldIdByCode(fieldCode);
        }
        log.warn("未找到字段名称对应的字段code: {}", fieldName);
        return null;
    }
    
    /**
     * 将字段名称映射到字段code
     */
    private String mapFieldNameToCode(String fieldName) {
        switch (fieldName) {
            case "申请人":
                return SystemFieldsEnum.APPLY_PEOPLE.getCode();
            case "合同名称":
                return SystemFieldsEnum.CONTRACT_NAME.getCode();
            case "合同编号":
                return SystemFieldsEnum.CONTRACT_NUMBER.getCode();
            case "合同类型":
                return SystemFieldsEnum.CONTRACT_TYPE.getCode();
            case "申请日期":
                return SystemFieldsEnum.APPLY_DATE.getCode();
            case "主合同文件":
                return "main_contract_file";
            case "对方":
                return "opposite";
            case "我方":
                return "our";
            default:
                return null;
        }
    }

    /**
     * 从动态字段中获取指定字段名称的值
     *
     * @param contractId 合同ID
     * @param fieldName  字段名称
     * @return 字段值
     */
    private String getFieldValueByName(Integer contractId, String fieldName) {
        Long fieldId = getFieldIdByName(fieldName);
        if (fieldId == null) {
            return null;
        }

        List<ContractFieldValueEntity> fieldValues = contractFieldValueMapper.selectByContractId(contractId);
        for (ContractFieldValueEntity fieldValue : fieldValues) {
            if (fieldId.equals(fieldValue.getFieldId())) {
                return fieldValue.getFieldValue();
            }
        }
        return null;
    }

    /**
     * 从动态字段中获取合同类型ID（从请求参数中直接获取）
     *
     * @param dynamicFields 动态字段集合
     * @return 合同类型ID
     */
    private Integer getContractTypeIdFromRequest(Map<Long, Object> dynamicFields) {
        if (dynamicFields == null || dynamicFields.isEmpty()) {
            return null;
        }

        // 查找合同类型字段的值
        Long contractTypeFieldId = getFieldIdByCode(SystemFieldsEnum.CONTRACT_TYPE.getCode());
        if (contractTypeFieldId == null) {
            log.warn("无法获取合同类型字段ID");
            return null;
        }
        Object contractTypeValue = dynamicFields.get(contractTypeFieldId);
        if (contractTypeValue != null) {
            try {
                return Integer.parseInt(contractTypeValue.toString());
            } catch (NumberFormatException e) {
                log.error("合同类型字段值格式错误: {}", contractTypeValue, e);
                return null;
            }
        }
        return null;
    }

    /**
     * 判断是否是申请日期字段
     *
     * @param fieldId 字段ID
     * @return 是否是申请日期字段
     */
    private boolean isApplyDateField(Long fieldId) {
        // 申请日期字段
        Long applyDateFieldId = getFieldIdByCode(SystemFieldsEnum.APPLY_DATE.getCode());
        return applyDateFieldId != null && fieldId != null && fieldId.equals(applyDateFieldId);
    }

    /**
     * 自动设置申请日期为当前日期
     *
     * @param dynamicFields 动态字段集合
     */
    private void autoSetApplyDate(Map<Long, Object> dynamicFields) {
        // 先通过字段code查询申请日期字段ID
        Long applyDateFieldId = getFieldIdByCode(SystemFieldsEnum.APPLY_DATE.getCode());
        if (applyDateFieldId != null) {
            // 自动设置申请日期为当前日期
            dynamicFields.put(applyDateFieldId, LocalDateTime.now());
            log.info("自动设置申请日期为当前日期: {}", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
        } else {
            log.warn("未找到申请日期字段配置，无法自动设置申请日期");
        }
    }

    // ==================== 枚举转换方法 ====================

    /**
     * 将交易方性质code转换为描述
     *
     * @param natureCode 性质code
     * @return 性质描述
     */
    private String convertCounterpartyNatureToDesc(Integer natureCode) {
        if (natureCode == null) {
            return null;
        }
        CounterpartyNatureEnum natureEnum = CounterpartyNatureEnum.getByCode(natureCode);
        return natureEnum != null ? natureEnum.getName() : null;
    }

    /**
     * 将交易方类型code转换为描述
     *
     * @param typeCode 类型code
     * @return 类型描述
     */
    private String convertCounterpartyTypeToDesc(Integer typeCode) {
        if (typeCode == null) {
            return null;
        }
        CounterpartyTypeEnum typeEnum = CounterpartyTypeEnum.getByCode(typeCode);
        return typeEnum != null ? typeEnum.getDesc() : null;
    }

    /**
     * 将证件类型code转换为描述
     *
     * @param certTypeCode 证件类型code
     * @return 证件类型描述
     */
    private String convertCertificateTypeToDesc(Integer certTypeCode) {
        if (certTypeCode == null) {
            return null;
        }
        CertificateTypeEnum certEnum = CertificateTypeEnum.getByCode(certTypeCode);
        return certEnum != null ? certEnum.getName() : null;
    }

    /**
     * 将国家代码转换为国家名称
     *
     * @param countryCode 国家代码
     * @return 国家名称
     */
    private String convertCountryCodeToName(String countryCode) {
        if (countryCode == null) {
            return null;
        }
        return countryDictService.getCountryNameByCode(countryCode);
    }

    /**
     * 根据员工ID列表获取员工信息 - 用于替换原来的permissionFeign调用
     *
     * @param employeeIds 员工ID列表
     * @return 员工信息列表
     */
    public List<EmployeeQueryShowVO> getUserByIds(List<Long> employeeIds) {
        if (employeeIds == null || employeeIds.isEmpty()) {
            log.warn("员工ID列表为空，返回空结果");
            return new ArrayList<>();
        }

        try {
            EmployeeQueryById queryRequest = new EmployeeQueryById();
            queryRequest.setEmployeeIds(employeeIds);
            List<EmployeeQueryShowVO> employeeList = sysUserService.queryEmployeeShow(queryRequest);

            if (employeeList == null || employeeList.isEmpty()) {
                log.info("根据员工ID列表未找到符合条件的员工信息，员工ID列表：{}", employeeIds);
                return new ArrayList<>();
            }

            log.info("根据员工ID列表成功查询到{}名员工，输入ID数量：{}", employeeList.size(), employeeIds.size());
            return employeeList;
        } catch (Exception e) {
            log.error("根据员工ID列表查询员工信息时发生异常，员工ID列表：{}", employeeIds, e);
            return new ArrayList<>();
        }
    }

    /**
     * 为合同字段中的对方和我方字段填充详细信息
     */
    private void fillCounterpartyAndOurPartyFieldDesc(ContractDTO contractDTO) {
        if (contractDTO.getFields() == null) {
            return;
        }

        for (ContractDTO.ModuleDTO.FieldDTO field : contractDTO.getFields()) {
            if (field.getId() == null || field.getFieldValue() == null) {
                continue;
            }

            // 通过字段code查询对方和我方字段ID
            Long counterpartyFieldId = getFieldIdByCode("opposite");
            Long ourPartyFieldId = getFieldIdByCode("our");
            
            // 处理对方字段
            if (counterpartyFieldId != null && field.getId().equals(counterpartyFieldId)) {
                fillCounterpartyFieldDesc(field);
            }
            // 处理我方字段
            else if (ourPartyFieldId != null && field.getId().equals(ourPartyFieldId)) {
                fillOurPartyFieldDesc(field);
            }
        }
    }

    /**
     * 填充对方字段的详细描述信息
     */
    private void fillCounterpartyFieldDesc(ContractDTO.ModuleDTO.FieldDTO field) {
        List<Map<String, Object>> result = new ArrayList<>();

        try {
            // 解析fieldValue，单个ID或ID数组
            List<Integer> counterpartyIds = parseIdsFromJson(field.getFieldValue());

            if (!counterpartyIds.isEmpty()) {
                List<CounterpartyInfoEntity> counterparties = counterpartyInfoMapper.selectByIds(counterpartyIds);
                for (CounterpartyInfoEntity counterparty : counterparties) {
                    // 处理 counterpartyType 可能为 null 的情况
                    List<Integer> list = new ArrayList<>();
                    if (counterparty.getCounterpartyType() != null && !counterparty.getCounterpartyType().trim().isEmpty()) {
                        list = Arrays.stream(counterparty.getCounterpartyType().split(","))
                                .map(String::trim)
                                .filter(s -> !s.isEmpty())
                                .map(Integer::parseInt)
                                .toList();
                    }

                    Map<String, Object> info = new HashMap<>();
                    info.put("id", counterparty.getId());
                    info.put("counterpartyCode", counterparty.getCounterpartyCode());
                    info.put("counterpartyName", counterparty.getCounterpartyName());
                    info.put("registerCountry", counterparty.getRegisterCountry());
                    info.put("registerCountryName", convertCountryCodeToName(counterparty.getRegisterCountry()));
                    info.put("counterpartyNature", counterparty.getCounterpartyNature());
                    info.put("counterpartyNatureDesc", convertCounterpartyNatureToDesc(counterparty.getCounterpartyNature()));
                    info.put("counterpartyType", list);
                    info.put("counterpartyTypeDesc", list.stream().map(this::convertCounterpartyTypeToDesc).toList());
                    info.put("isRelatedParty", counterparty.getIsRelatedParty());
                    info.put("certificateType", counterparty.getCertificateType());
                    info.put("certificateTypeDesc", convertCertificateTypeToDesc(counterparty.getCertificateType()));
                    info.put("certificateId", counterparty.getCertificateId());
                    info.put("isEnabled", counterparty.getIsEnabled());
                    info.put("createdAt", formatTimeField(counterparty.getCreatedAt()));

                    // 获取银行信息
                    if (counterparty.getBankInfoIds() != null && !counterparty.getBankInfoIds().isEmpty()) {
                        List<Integer> bankIds = Arrays.stream(counterparty.getBankInfoIds().split(","))
                                .map(String::trim)
                                .filter(s -> !s.isEmpty())
                                .map(Integer::parseInt)
                                .collect(Collectors.toList());

                        if (!bankIds.isEmpty()) {
                            List<BankInfoEntity> bankInfos = bankInfoMapper.selectByIds(bankIds);
                            List<BankInfoDTO> bankInfoDTOs = bankInfos.stream()
                                    .map(bank -> {
                                        BankInfoDTO bankDTO = new BankInfoDTO();
                                        BeanUtils.copyProperties(bank, bankDTO);
                                        // 设置银行国家代码和名称
                                        bankDTO.setBankCountryCode(bank.getBankCountry());
                                        bankDTO.setBankCountry(bank.getBankCountry());
                                        bankDTO.setBankCountryName(convertCountryCodeToName(bank.getBankCountry()));
                                        // 设置兼容字段
                                        bankDTO.setBankAccount(bank.getAccountNumber());
                                        return bankDTO;
                                    })
                                    .collect(Collectors.toList());
                            info.put("bankInfoList", bankInfoDTOs);
                        }
                    }

                    result.add(info);
                }
            }
        } catch (Exception e) {
            log.error("填充对方字段详细信息失败，字段值: {}", field.getFieldValue(), e);
        }

        if (!result.isEmpty()) {
            field.setFieldDesc(result);
        }
    }

    /**
     * 填充我方字段的详细描述信息
     */
    private void fillOurPartyFieldDesc(ContractDTO.ModuleDTO.FieldDTO field) {
        List<Map<String, Object>> result = new ArrayList<>();

        try {
            // 解析fieldValue，可能是单个ID或ID数组
            List<Integer> legalEntityIds = parseIdsFromJson(field.getFieldValue());

            if (!legalEntityIds.isEmpty()) {
                List<LegalEntityDetailEntity> legalEntities = legalEntityDetailMapper.selectByIds(legalEntityIds);
                for (LegalEntityDetailEntity legalEntity : legalEntities) {
                    Map<String, Object> info = new HashMap<>();
                    info.put("id", legalEntity.getId());
                    info.put("legalEntityCode", legalEntity.getLegalEntityCode());
                    info.put("legalEntityName", legalEntity.getLegalEntityName());
                    info.put("legalEntityAbbr", legalEntity.getLegalEntityAbbr());
                    info.put("registerCountry", legalEntity.getRegisterCountry());
                    info.put("registerCountryName", convertCountryCodeToName(legalEntity.getRegisterCountry()));
                    info.put("detailAddress", legalEntity.getDetailAddress());
                    info.put("certificateType", legalEntity.getCertificateType());
                    info.put("certificateId", legalEntity.getCertificateId());
                    info.put("isEnabled", legalEntity.getIsEnabled());
                    info.put("statusText", legalEntity.getIsEnabled() ? "启用" : "停用");
                    info.put("createdAt", formatTimeField(legalEntity.getCreatedAt()));
                    info.put("updatedAt", formatTimeField(legalEntity.getUpdatedAt()));

                    // 获取银行信息
                    if (legalEntity.getBankInfoIds() != null && !legalEntity.getBankInfoIds().isEmpty()) {
                        List<Integer> bankIds = Arrays.stream(legalEntity.getBankInfoIds().split(","))
                                .map(String::trim)
                                .filter(s -> !s.isEmpty())
                                .map(Integer::parseInt)
                                .collect(Collectors.toList());

                        if (!bankIds.isEmpty()) {
                            List<BankInfoEntity> bankInfos = bankInfoMapper.selectByIds(bankIds);
                            List<BankInfoDTO> bankInfoDTOs = bankInfos.stream()
                                    .map(bank -> {
                                        BankInfoDTO bankDTO = new BankInfoDTO();
                                        BeanUtils.copyProperties(bank, bankDTO);
                                        // 设置银行国家代码和名称
                                        bankDTO.setBankCountryCode(bank.getBankCountry());
                                        bankDTO.setBankCountry(bank.getBankCountry());
                                        bankDTO.setBankCountryName(convertCountryCodeToName(bank.getBankCountry()));
                                        // 设置兼容字段
                                        bankDTO.setBankAccount(bank.getAccountNumber());
                                        return bankDTO;
                                    })
                                    .collect(Collectors.toList());
                            info.put("bankInfoList", bankInfoDTOs);
                        }
                    }

                    result.add(info);
                }
            }
        } catch (Exception e) {
            log.error("填充我方字段详细信息失败，字段值: {}", field.getFieldValue(), e);
        }

        if (!result.isEmpty()) {
            field.setFieldDesc(result);
        }
    }

    /**
     * 处理字段值和字段描述
     */
    private void processFieldValuesAndDescriptions(ContractDTO contractDTO) {
        if (contractDTO.getFields() == null) {
            return;
        }

        for (ContractDTO.ModuleDTO.FieldDTO field : contractDTO.getFields()) {
            if (field.getId() == null) {
                continue;
            }

            // 处理字段值转换（下拉选项等）
            processFieldValueConversion(field);

            // 处理字段描述信息
            processFieldDescription(field, contractDTO.getId());
        }
    }

    /**
     * 处理字段值转换（主要是下拉选项的code转message）
     */
    private void processFieldValueConversion(ContractDTO.ModuleDTO.FieldDTO field) {
        if (field.getFieldValue() == null || field.getFieldValue().isEmpty()) {
            return;
        }

        // 处理下拉选项字段
        if (field.getFieldOptions() != null && !field.getFieldOptions().isEmpty()) {
            log.info("处理字段值转换 - 字段ID: {}, 字段名: {}, 原始值: {}, fieldOptions: {}",
                    field.getId(), field.getFieldName(), field.getFieldValue(), field.getFieldOptions());

            String convertedValue = convertFieldValueByOptions(field.getFieldValue(), field.getFieldOptions());
            if (convertedValue != null) {
                log.info("字段值转换成功 - 字段ID: {}, 原始值: {} -> 新值: {}",
                        field.getId(), field.getFieldValue(), convertedValue);
                field.setFieldValue(convertedValue);
            } else {
                log.info("字段值转换失败，保持原值 - 字段ID: {}, 值: {}", field.getId(), field.getFieldValue());
            }
        } else {
            log.debug("字段没有fieldOptions，跳过转换 - 字段ID: {}, 字段名: {}", field.getId(), field.getFieldName());
        }
    }

    /**
     * 根据fieldOptions将code转换为对应的message
     */
    private String convertFieldValueByOptions(String fieldValue, Map<String, Object> fieldOptions) {
        try {
            log.debug("开始转换字段值 - fieldValue: {}, fieldOptions: {}", fieldValue, fieldOptions);

            // 解析fieldOptions中的options数组
            Object optionsObj = fieldOptions.get("options");
            if (optionsObj == null) {
                log.warn("fieldOptions中没有options字段");
                return null;
            }

            if (!(optionsObj instanceof List)) {
                log.warn("options字段不是List类型，实际类型: {}", optionsObj.getClass().getName());
                return null;
            }

            List<?> options = (List<?>) optionsObj;

            for (Object optionObj : options) {
                if (optionObj instanceof Map) {
                    Map<?, ?> option = (Map<?, ?>) optionObj;
                    Object keyObj = option.get("key");
                    Object valueObj = option.get("value");
                    if (keyObj == null || valueObj == null) {
                        continue;
                    }
                    String key = String.valueOf(keyObj);
                    String value = String.valueOf(valueObj);
                    // 如果找到匹配的key，返回对应的value
                    if (fieldValue.equals(key)) {
                        return value;
                    }
                } else {
                }
            }
        } catch (Exception e) {
            log.error("转换字段值失败，fieldValue: {}, fieldOptions: {}", fieldValue, fieldOptions, e);
        }

        // 如果没有找到匹配的，返回null（保持原值）
        return null;
    }

    /**
     * 处理字段描述信息
     */
    private void processFieldDescription(ContractDTO.ModuleDTO.FieldDTO field, Integer contractId) {
        if (field.getFieldValue() == null || field.getFieldValue().isEmpty()) {
            return;
        }

        // 通过字段code查询对方和我方字段ID
        Long counterpartyFieldId = getFieldIdByCode("opposite");
        Long ourPartyFieldId = getFieldIdByCode("our");
        
        // 根据字段ID和字段类型处理不同的字段描述
        if (counterpartyFieldId != null && field.getId().equals(counterpartyFieldId)) {
            // 对方字段：填充交易方详细信息
            fillCounterpartyFieldDesc(field);
        } else if (ourPartyFieldId != null && field.getId().equals(ourPartyFieldId)) {
            // 我方字段：填充法人实体详细信息
            fillOurPartyFieldDesc(field);
        } else {
            // 检查是否为主合同文件字段
            Long mainContractFieldId = getFieldIdByCode(SystemFieldsEnum.MAIN_CONTRACT_FILE.getCode());
            if (mainContractFieldId != null && field.getId().equals(mainContractFieldId)) {
                // 主合同文件字段：添加版本信息
                fillMainContractFileVersionDesc(field, contractId);
            } else if ("PERSON".equalsIgnoreCase(field.getFieldType())) {
                // 人员字段：查询用户信息放到fieldDesc中
                fillPersonFieldDescForList(field);
            } else if (isContractAttachmentField(field.getId())) {
                // 合同附件字段：查询文件信息并添加确认状态
                fillContractAttachmentFieldDesc(field, contractId);
            } else if ("ATTACHMENT".equalsIgnoreCase(field.getFieldType())) {
                // 其他附件字段：查询文件信息放到fieldDesc中
                fillAttachmentFieldDescForList(field);
            } else if ("linked_contract".equalsIgnoreCase(field.getFieldType())) {
                // 关联合同字段：查询关联合同信息放到fieldDesc中
                fillLinkedContractFieldDesc(field);
            }
        }
        // 其他字段类型暂不处理特殊的fieldDesc
    }

    /**
     * 为人员字段填充用户信息到fieldDesc中（合同列表使用）
     */
    private void fillPersonFieldDescForList(ContractDTO.ModuleDTO.FieldDTO field) {
        List<Map<String, Object>> result = new ArrayList<>();

        try {
            // 解析用户ID，可能是单个ID或多个ID
            List<Long> userIds = parseUserIds(field.getFieldValue());

            if (!userIds.isEmpty()) {
                // 批量查询用户信息
                EmployeeQueryById queryRequest = new EmployeeQueryById();
                queryRequest.setEmployeeIds(userIds);
                List<EmployeeQueryShowVO> employees = sysUserService.queryEmployeeShow(queryRequest);

                for (EmployeeQueryShowVO employee : employees) {
                    Map<String, Object> userInfo = new HashMap<>();
                    userInfo.put("id", employee.getId());
                    userInfo.put("name", employee.getName());
                    userInfo.put("aliasName", employee.getAliasName());
                    userInfo.put("avatar", employee.getAvatar());
                    // 使用统一的部门获取方法（优先主部门，无租户隔离）
                    String deptName = getUserDepartment(employee.getId());
                    userInfo.put("deptName", deptName);

                    result.add(userInfo);
                }
            }
        } catch (Exception e) {
            log.error("填充人员字段详细信息失败，字段值: {}", field.getFieldValue(), e);
        }

        if (!result.isEmpty()) {
            field.setFieldDesc(result);
        }
    }

    /**
     * 为附件字段填充文件信息到fieldDesc中（合同列表和详情使用）
     */
    private void fillAttachmentFieldDescForList(ContractDTO.ModuleDTO.FieldDTO field) {
        List<Map<String, Object>> result = new ArrayList<>();

        try {
            // 解析fieldValue，可能是单个文件ID或文件ID数组
            List<String> fileIds = parseFileIds(field.getFieldValue());

            for (String fileId : fileIds) {
                try {
                    SingleResponse<FileVO> response = fileInfoService.getFileInfoById(fileId);
                    if (response.isSuccess() && response.getData() != null) {
                        FileVO file = response.getData();
                        Map<String, Object> fileInfo = new HashMap<>();
                        fileInfo.put("fileId", file.getFileId());
                        fileInfo.put("fileName", file.getFileName());
                        fileInfo.put("fileKey", file.getFileKey());
                        fileInfo.put("fileSize", file.getFileSize());
                        fileInfo.put("fileType", file.getFileType());
                        fileInfo.put("createTime", formatTimeField(file.getCreateTime()));
                        result.add(fileInfo);
                    }
                } catch (Exception e) {
                    log.error("获取文件信息失败，fileId: {}", fileId, e);
                }
            }
        } catch (Exception e) {
            log.error("填充附件字段详细信息失败，字段值: {}", field.getFieldValue(), e);
        }

        if (!result.isEmpty()) {
            field.setFieldDesc(result);
        }
    }

    /**
     * 为合同附件字段（ID=21）填充文件信息和确认状态到fieldDesc中
     */
    private void fillContractAttachmentFieldDesc(ContractDTO.ModuleDTO.FieldDTO field, Integer contractId) {
        List<Map<String, Object>> result = new ArrayList<>();

        try {
            // 获取当前用户ID
            UserInfo currentUser = AuthUtil.getCurrentUser();
            Long currentUserId = (currentUser != null && currentUser.getId() != null) ? currentUser.getId() : null;

            // 解析fieldValue，可能是单个文件ID或文件ID数组
            List<String> fileIds = parseFileIds(field.getFieldValue());

            for (String fileId : fileIds) {
                try {
                    SingleResponse<FileVO> response = fileInfoService.getFileInfoById(fileId);
                    if (response.isSuccess() && response.getData() != null) {
                        FileVO file = response.getData();
                        Map<String, Object> fileInfo = new HashMap<>();
                        fileInfo.put("fileId", file.getFileId());
                        fileInfo.put("fileName", file.getFileName());
                        fileInfo.put("fileKey", file.getFileKey());
                        fileInfo.put("fileSize", file.getFileSize());
                        fileInfo.put("fileType", file.getFileType());
                        fileInfo.put("createTime", formatTimeField(file.getCreateTime()));

                        // 添加确认状态
                        boolean isConfirmed = false;
                        if (currentUserId != null) {
                            isConfirmed = checkFileConfirmStatus(contractId, Integer.parseInt(fileId), currentUserId);
                        }
                        fileInfo.put("isConfirmed", isConfirmed);

                        result.add(fileInfo);
                    }
                } catch (Exception e) {
                    log.error("获取文件信息失败，fileId: {}", fileId, e);
                }
            }
        } catch (Exception e) {
            log.error("填充合同附件字段详细信息失败，字段值: {}", field.getFieldValue(), e);
        }

        if (!result.isEmpty()) {
            field.setFieldDesc(result);
        }
    }

    /**
     * 为关联合同字段填充关联合同信息到fieldDesc中
     */
    private void fillLinkedContractFieldDesc(ContractDTO.ModuleDTO.FieldDTO field) {
        List<Map<String, Object>> result = new ArrayList<>();

        try {
            // 解析fieldValue，应该是合同ID数组，格式如 [1,2,3]
            List<Integer> contractIds = parseContractIds(field.getFieldValue());

            for (Integer contractId : contractIds) {
                try {
                    // 查询合同基本信息
                    ContractEntity contract = contractMapper.selectById(contractId);
                    if (contract == null) {
                        log.warn("关联合同不存在，合同ID: {}", contractId);
                        continue;
                    }

                    // 构建关联合同信息（复用简化合同列表的逻辑）
                    Map<String, Object> contractInfo = buildLinkedContractInfo(contract);
                    if (contractInfo != null) {
                        result.add(contractInfo);
                    }

                } catch (Exception e) {
                    log.error("获取关联合同信息失败，合同ID: {}", contractId, e);
                }
            }
        } catch (Exception e) {
            log.error("填充关联合同字段详细信息失败，字段值: {}", field.getFieldValue(), e);
        }

        if (!result.isEmpty()) {
            field.setFieldDesc(result);
        }
    }

    /**
     * 解析合同ID数组
     */
    private List<Integer> parseContractIds(String fieldValue) {
        List<Integer> contractIds = new ArrayList<>();

        if (fieldValue == null || fieldValue.trim().isEmpty()) {
            return contractIds;
        }

        try {
            // 清理字符串，移除方括号和空格
            String cleanValue = fieldValue.replaceAll("[\\[\\]\\s]", "");

            if (!cleanValue.isEmpty()) {
                String[] idArray = cleanValue.split(",");
                for (String idStr : idArray) {
                    try {
                        Integer contractId = Integer.parseInt(idStr.trim());
                        contractIds.add(contractId);
                    } catch (NumberFormatException e) {
                        log.warn("解析合同ID失败: {}", idStr);
                    }
                }
            }
        } catch (Exception e) {
            log.error("解析合同ID数组失败，原始值: {}", fieldValue, e);
        }

        return contractIds;
    }

    /**
     * 根据字段ID获取字段编码
     */
    private String getFieldCodeById(Long fieldId) {
        try {
            if (fieldId == null) {
                return null;
            }

            ContractFieldEntity field = contractFieldMapper.selectById(fieldId);
            if (field != null) {
                return field.getCode();
            } else {
                log.warn("未找到字段信息，字段ID: {}", fieldId);
                return null;
            }
        } catch (Exception e) {
            log.error("获取字段编码失败，字段ID: {}", fieldId, e);
            return null;
        }
    }

    /**
     * 构建关联合同信息（复用简化合同列表的逻辑）
     */
    private Map<String, Object> buildLinkedContractInfo(ContractEntity contract) {
        try {
            Map<String, Object> contractInfo = new HashMap<>();

            // 基本信息
            contractInfo.put("contractId", contract.getId());
            contractInfo.put("contractStatus", contract.getCurrentStatus());

            // 查询动态字段值
            List<ContractFieldValueEntity> fieldValues = contractFieldValueMapper.selectByContractId(contract.getId());
            Map<String, String> fieldValueMap = new HashMap<>();

            for (ContractFieldValueEntity fieldValue : fieldValues) {
                ContractFieldEntity field = contractFieldMapper.selectById(fieldValue.getFieldId());
                if (field != null) {
                    fieldValueMap.put(field.getCode(), fieldValue.getFieldValue());
                }
            }

            // 设置合同名称和编码
            contractInfo.put("contractName", fieldValueMap.get("contract_name"));
            contractInfo.put("contractCode", fieldValueMap.get("contract_number"));

            // 设置申请人信息
            String applyPeopleId = fieldValueMap.get("apply_people");
            if (applyPeopleId != null) {
                try {
                    SysUser applicant = sysUserService.getById(Long.parseLong(applyPeopleId));
                    if (applicant != null) {
                        contractInfo.put("applicantName", applicant.getNickName());
                        contractInfo.put("applicantAvatar", applicant.getAvatar());
                    }
                } catch (Exception e) {
                    log.warn("获取申请人信息失败，ID: {}", applyPeopleId);
                }
            }

            // 设置交易方名称列表
            String oppositeIds = fieldValueMap.get("opposite");
            List<String> counterpartyNames = new ArrayList<>();
            if (oppositeIds != null) {
                try {
                    String cleanIds = oppositeIds.replaceAll("[\\[\\]\\s]", "");
                    if (!cleanIds.isEmpty()) {
                        String[] idArray = cleanIds.split(",");
                        for (String idStr : idArray) {
                            try {
                                CounterpartyInfoEntity counterparty = counterpartyService.getById(Integer.parseInt(idStr.trim()));
                                if (counterparty != null && counterparty.getCounterpartyName() != null) {
                                    counterpartyNames.add(counterparty.getCounterpartyName());
                                }
                            } catch (Exception e) {
                                log.warn("解析交易方ID失败: {}", idStr);
                            }
                        }
                    }
                } catch (Exception e) {
                    log.warn("获取交易方信息失败，IDs: {}", oppositeIds);
                }
            }
            contractInfo.put("counterpartyNames", counterpartyNames);

            return contractInfo;

        } catch (Exception e) {
            log.error("构建关联合同信息失败，合同ID: {}", contract.getId(), e);
            return null;
        }
    }

    /**
     * 检查指定文件的确认状态
     *
     * @param contractId 合同ID
     * @param fileId     文件ID
     * @param userId     用户ID
     * @return 是否已确认
     */
    private boolean checkFileConfirmStatus(Integer contractId, Integer fileId, Long userId) {
        try {
            ContractAttachmentConfirmEntity confirmRecord = contractAttachmentConfirmMapper.selectOne(
                    new LambdaQueryWrapper<ContractAttachmentConfirmEntity>()
                            .eq(ContractAttachmentConfirmEntity::getContractId, contractId)
                            .eq(ContractAttachmentConfirmEntity::getFileId, fileId)
                            .eq(ContractAttachmentConfirmEntity::getUserId, userId)
            );

            return confirmRecord != null && confirmRecord.getIsConfirmed() != null && confirmRecord.getIsConfirmed() == 1;
        } catch (Exception e) {
            log.error("检查文件确认状态失败，合同ID: {}, 文件ID: {}, 用户ID: {}", contractId, fileId, userId, e);
            return false;
        }
    }

    /**
     * 为主合同文件字段（ID=20）填充版本信息到fieldDesc中
     */
    private void fillMainContractFileVersionDesc(ContractDTO.ModuleDTO.FieldDTO field, Integer contractId) {
        List<Map<String, Object>> result = new ArrayList<>();

        try {
            // 解析文件ID
            Long fileId = Long.parseLong(field.getFieldValue());

            // 获取文件基本信息
            SingleResponse<FileVO> response = fileInfoService.getFileInfoById(fileId.toString());
            if (response.isSuccess() && response.getData() != null) {
                FileVO file = response.getData();
                Map<String, Object> fileInfo = new HashMap<>();
                fileInfo.put("fileId", file.getFileId());
                fileInfo.put("fileName", file.getFileName());
                fileInfo.put("fileKey", file.getFileKey());
                fileInfo.put("fileSize", file.getFileSize());
                fileInfo.put("fileType", file.getFileType());
                fileInfo.put("createTime", formatTimeField(file.getCreateTime()));

                // 查询contract_file表获取最大版本号
                String version = getContractFileMaxVersion(contractId, fileId);
                if (version != null && !version.isEmpty()) {
                    fileInfo.put("version", version);
                    log.info("主合同文件版本信息 - 合同ID: {}, 文件ID: {}, 版本: {}", contractId, fileId, version);
                } else {
                    log.info("主合同文件未找到版本信息 - 合同ID: {}, 文件ID: {}", contractId, fileId);
                }

                result.add(fileInfo);
            }
        } catch (Exception e) {
            log.error("填充主合同文件版本信息失败，字段值: {}, 合同ID: {}", field.getFieldValue(), contractId, e);
        }

        if (!result.isEmpty()) {
            field.setFieldDesc(result);
        }
    }

    /**
     * 根据合同ID和文件ID获取contract_file表中的最大版本号
     *
     * @param contractId 合同ID
     * @param fileId     文件ID
     * @return 版本字符串，格式为"V1.0"，如果没有找到则返回null
     */
    private String getContractFileMaxVersion(Integer contractId, Long fileId) {
        try {
            // 查询该合同该文件的最高版本记录
            ContractFileEntity latestVersion = contractFileService.getOne(
                    new LambdaQueryWrapper<ContractFileEntity>()
                            .eq(ContractFileEntity::getContractId, contractId)
                            .eq(ContractFileEntity::getFileId, fileId)
                            .orderByDesc(ContractFileEntity::getMajorVersion)
                            .orderByDesc(ContractFileEntity::getMinorVersion)
                            .last("LIMIT 1")
            );

            if (latestVersion != null) {
                return String.format("V%d.%d", latestVersion.getMajorVersion(), latestVersion.getMinorVersion());
            }

            return null;
        } catch (Exception e) {
            log.error("获取合同文件最大版本失败，合同ID: {}, 文件ID: {}", contractId, fileId, e);
            return null;
        }
    }

    /**
     * 创建新的合同文件版本记录
     *
     * @param contractId 合同ID
     * @param fileId     新文件ID
     */
    private void createNewContractFileVersion(Integer contractId, Long fileId) {
        try {
            // 查找当前合同的最高major_version
            ContractFileEntity latestVersion = contractFileService.getOne(
                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<ContractFileEntity>()
                            .eq(ContractFileEntity::getContractId, contractId)
                            .orderByDesc(ContractFileEntity::getMajorVersion)
                            .orderByDesc(ContractFileEntity::getMinorVersion)
                            .last("LIMIT 1")
            );

            // 计算新的主版本号
            Integer newMajorVersion = 1;
            if (latestVersion != null) {
                newMajorVersion = latestVersion.getMajorVersion() + 1;
            }

            // 获取当前用户ID（使用与其他地方一致的UserSession方式）
            Long currentUserId = UserSession.getLoginInfo().getId();
            if (currentUserId == null) {
                throw new RuntimeException("无法获取当前用户ID");
            }

            // 获取文件历史版本号
            Integer fileHistoryVersion = getFileHistoryVersion(fileId);

            // 创建新的文件版本记录
            ContractFileEntity newVersion = new ContractFileEntity()
                    .setContractId(contractId)
                    .setMajorVersion(newMajorVersion)
                    .setMinorVersion(0) // 新主版本，次版本重置为0
                    .setFileId(fileId)
                    .setCreateId(currentUserId)
                    .setUpdateBy(currentUserId)
                    .setCreateTime(java.time.LocalDateTime.now())
                    .setUpdateTime(java.time.LocalDateTime.now());

            // 只有在找到有效的文件历史版本时才设置该字段
            if (fileHistoryVersion != null) {
                newVersion.setFileHistoryVersion(fileHistoryVersion);
                log.info("修改合同设置文件历史版本号: {}", fileHistoryVersion);
            } else {
                log.info("修改合同未设置文件历史版本号（未找到有效数据）");
            }

            contractFileService.save(newVersion);

            log.info("创建新合同文件版本成功，合同ID: {}, 文件ID: {}, 版本: {}.{}",
                    contractId, fileId, newMajorVersion, 0);

        } catch (Exception e) {
            log.error("创建新合同文件版本失败，合同ID: {}, 文件ID: {}", contractId, fileId, e);
            throw new RuntimeException("创建新合同文件版本失败", e);
        }
    }

    /**
     * 记录文件更新操作日志
     *
     * @param contractId 合同ID
     * @param fileId     文件ID
     */
    private void recordFileUpdateLog(Integer contractId, Long fileId) {
        try {
            // 获取当前用户ID（使用与其他地方一致的UserSession方式）
            Long currentUserId = UserSession.getLoginInfo().getId();
            if (currentUserId == null) {
                throw new RuntimeException("无法获取当前用户ID");
            }

            // 构建扩展数据（参考发起协商和确认协商的方式）
            Map<String, Object> extData = new HashMap<>();
            extData.put("mainContractFileId", fileId);

            // 获取文件版本信息（参考发起协商和确认协商的方式）
            String version = getFileVersionInfo(contractId, fileId);
            if (version != null) {
                extData.put("version", version);
                log.info("添加版本信息到扩展数据: {}", version);
            } else {
                log.info("未获取到版本信息，不添加version字段");
            }

            // 创建操作日志记录
            ContractOperationLog operationLog = ContractOperationLog.builder()
                    .contractId(contractId.longValue())
                    .flowType(WorkFlowTypeEnums.NEGOTIATION_WORKFLOW.getCode())
                    .actionType(ActionTypeEnums.UPDATE_FILE.getCode())
                    .sourceType(SourceTypeEnums.USER.getCode())
                    .userId(currentUserId)
                    .actionTime(new java.util.Date())
                    .extData(com.alibaba.fastjson.JSON.toJSONString(extData))
                    .build();

            contractOperationLogService.save(operationLog);

            log.info("记录文件更新操作日志成功，合同ID: {}, 文件ID: {}, 用户ID: {}, ext_data: {}",
                    contractId, fileId, currentUserId, operationLog.getExtData());

        } catch (Exception e) {
            log.error("记录文件更新操作日志失败，合同ID: {}, 文件ID: {}", contractId, fileId, e);
            throw new RuntimeException("记录文件更新操作日志失败", e);
        }
    }


    /**
     * 获取file_history表中指定文件的最高版本号
     *
     * @param fileId 文件ID
     * @return 最高版本号（整数形式），如果没有数据或version为空则返回null
     */
    private Integer getFileHistoryVersion(Long fileId) {
        try {
            FileHistory latestHistory = fileHistoryMapper.selectOne(
                    new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<FileHistory>()
                            .eq(FileHistory::getFileId, fileId)
                            .isNotNull(FileHistory::getVersion) // 只查询version不为空的记录
                            .orderByDesc(FileHistory::getVersion)
                            .last("LIMIT 1")
            );

            if (latestHistory != null && latestHistory.getVersion() != null) {
                log.info("找到文件历史版本，文件ID: {}, 版本号: {}", fileId, latestHistory.getVersion());
                return latestHistory.getVersion();
            } else {
                log.info("未找到文件历史版本数据或version为空，文件ID: {}", fileId);
                return null;
            }
        } catch (Exception e) {
            log.error("获取文件历史最高版本失败，文件ID: {}", fileId, e);
            return null;
        }
    }

    /**
     * 格式化时间字段，将时间戳或LocalDateTime转换为格式化字符串
     *
     * @param timeValue 时间值（可能是时间戳Long、LocalDateTime或其他）
     * @return 格式化的时间字符串，格式为"yyyy-MM-dd HH:mm:ss"
     */
    private String formatTimeField(Object timeValue) {
        if (timeValue == null) {
            return null;
        }

        try {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

            if (timeValue instanceof Long) {
                // 时间戳转换
                Long timestamp = (Long) timeValue;
                LocalDateTime dateTime = LocalDateTime.ofInstant(
                        java.time.Instant.ofEpochMilli(timestamp),
                        java.time.ZoneId.systemDefault()
                );
                return dateTime.format(formatter);
            } else if (timeValue instanceof LocalDateTime) {
                // LocalDateTime直接格式化
                return ((LocalDateTime) timeValue).format(formatter);
            } else if (timeValue instanceof Date) {
                // Date转换
                Date date = (Date) timeValue;
                LocalDateTime dateTime = date.toInstant()
                        .atZone(java.time.ZoneId.systemDefault())
                        .toLocalDateTime();
                return dateTime.format(formatter);
            } else {
                // 其他类型尝试转换为字符串
                return timeValue.toString();
            }
        } catch (Exception e) {
            log.warn("时间格式化失败，原值: {}, 类型: {}", timeValue, timeValue.getClass().getName(), e);
            return timeValue.toString();
        }
    }

    /**
     * 从动态字段中获取当前主合同文件ID
     *
     * @param contractId 合同ID
     * @return 主合同文件ID，如果未找到返回null
     */
    private Long getCurrentMainContractFileIdFromDynamicField(Integer contractId) {
        try {
            // 先通过字段code查询主合同文件字段ID
            Long mainContractFileFieldId = getFieldIdByCode("main_contract_file");
            if (mainContractFileFieldId == null) {
                log.warn("未找到主合同文件字段配置");
                return null;
            }
            
            ContractFieldValueEntity fieldValue = contractFieldValueMapper.selectOne(
                    new LambdaQueryWrapper<ContractFieldValueEntity>()
                            .eq(ContractFieldValueEntity::getContractId, contractId)
                            .eq(ContractFieldValueEntity::getFieldId, mainContractFileFieldId)
            );

            if (fieldValue != null && fieldValue.getFieldValue() != null) {
                return Long.parseLong(fieldValue.getFieldValue());
            }

            return null;
        } catch (Exception e) {
            log.error("从动态字段获取主合同文件ID失败，合同ID: {}", contractId, e);
            return null;
        }
    }

    /**
     * 获取文件版本信息
     *
     * @param contractId 合同ID
     * @param fileId     文件ID
     * @return 版本信息，格式为"主合同 V{major_version}.{minor_version}"，如果没有找到则返回null
     */
    private String getFileVersionInfo(Integer contractId, Long fileId) {
        try {
            // 查询该文件的最高版本记录
            LambdaQueryWrapper<ContractFileEntity> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(ContractFileEntity::getContractId, contractId)
                    .eq(ContractFileEntity::getFileId, fileId)
                    .orderByDesc(ContractFileEntity::getMajorVersion)
                    .orderByDesc(ContractFileEntity::getMinorVersion)
                    .last("LIMIT 1");

            ContractFileEntity latestVersion = contractFileService.getOne(queryWrapper);

            if (latestVersion != null) {
                return String.format("主合同 V%d.%d",
                        latestVersion.getMajorVersion(),
                        latestVersion.getMinorVersion());
            }

            // 如果没有版本记录，返回null
            log.info("未找到文件版本记录，不添加版本信息，合同ID: {}, 文件ID: {}", contractId, fileId);
            return null;

        } catch (Exception e) {
            log.error("获取文件版本信息失败，不添加版本信息，合同ID: {}, 文件ID: {}", contractId, fileId, e);
            return null;
        }
    }

    @Override
    public ContractCountDTO getMyContractAndNegotiationCount(Long userId) {
        log.info("开始统计用户的合同和协商数量，用户ID: {}", userId);

        try {
            // 1. 统计我的合同数量（申请人是我且状态为审批中）
            Long myContractCount = countMyContractsInApproval(userId);
            log.info("用户 {} 的合同数量: {}", userId, myContractCount);

            // 2. 统计我的协商数量（申请人是我的协商实例，带多租户隔离）
            Long myNegotiationCount = countMyNegotiationsWithMultiTenant(userId);
            log.info("用户 {} 的协商数量（多租户隔离后）: {}", userId, myNegotiationCount);

            return new ContractCountDTO(myContractCount, myNegotiationCount);

        } catch (Exception e) {
            log.error("统计用户合同和协商数量失败，用户ID: {}", userId, e);
            return new ContractCountDTO(0L, 0L);
        }
    }

    /**
     * 统计我的合同数量（申请人是我且状态为审批中）
     */
    private Long countMyContractsInApproval(Long userId) {
        // 1. 先查询申请人是我的所有合同
        // 先通过字段code查询申请人字段ID
        Long applicantFieldId = getFieldIdByCode(SystemFieldsEnum.APPLY_PEOPLE.getCode());
        if (applicantFieldId == null) {
            log.warn("未找到申请人字段配置");
            return 0L;
        }
        
        List<ContractFieldValueEntity> myAppliedContracts = contractFieldValueMapper.selectList(
                new LambdaQueryWrapper<ContractFieldValueEntity>()
                        .eq(ContractFieldValueEntity::getFieldId, applicantFieldId)
                        .eq(ContractFieldValueEntity::getFieldValue, userId.toString())
        );

        if (myAppliedContracts.isEmpty()) {
            return 0L;
        }

        // 2. 获取我申请的合同ID列表
        List<Integer> contractIds = myAppliedContracts.stream()
                .map(ContractFieldValueEntity::getContractId)
                .collect(Collectors.toList());

        // 3. 查询这些合同中状态为IN_APPROVAL且在我有权限的租户中的合同
        LambdaQueryWrapper<ContractEntity> queryWrapper = new LambdaQueryWrapper<ContractEntity>()
                .in(ContractEntity::getId, contractIds)
                .eq(ContractEntity::getCurrentStatus, "IN_APPROVAL");

        // 4. 应用租户过滤 - 修改逻辑：优先使用当前租户，如果为空则使用租户列表
        UserInfo currentUser = AuthUtil.getCurrentUser();
        String currentSysTenantKey = currentUser != null ? currentUser.getSysTenantKey() : null;

        if (currentSysTenantKey != null && !currentSysTenantKey.trim().isEmpty()) {
            // 如果当前用户有明确的sysTenantKey，只查询该租户下的数据
            queryWrapper.eq(ContractEntity::getSysTenantKey, currentSysTenantKey);
            log.debug("使用当前租户过滤合同数据，租户键: {}", currentSysTenantKey);
        } else {
            // 如果sysTenantKey为null或空，使用原有逻辑（查询用户有权限的所有租户）
            List<String> userTenantKeys = AuthUtil.getUserTenantKeys();
            if (userTenantKeys != null && !userTenantKeys.isEmpty()) {
                queryWrapper.in(ContractEntity::getSysTenantKey, userTenantKeys);
                log.debug("使用租户列表过滤合同数据，租户键列表: {}", userTenantKeys);
            } else if (userTenantKeys != null) {
                // 空列表表示没有任何租户权限
                queryWrapper.eq(ContractEntity::getSysTenantKey, "NO_PERMISSION");
                log.warn("用户没有任何租户权限");
            }
        }

        return contractMapper.selectCount(queryWrapper);
    }

    /**
     * 统计我的协商数量（支持多租户权限判断）
     */
    private Long countMyNegotiationsWithMultiTenant(Long userId) {
        // 修改逻辑：优先使用当前租户，如果为空则使用租户列表
        UserInfo currentUser = AuthUtil.getCurrentUser();
        String currentSysTenantKey = currentUser != null ? currentUser.getSysTenantKey() : null;

        if (currentSysTenantKey != null && !currentSysTenantKey.trim().isEmpty()) {
            // 如果当前用户有明确的sysTenantKey，只查询该租户下的数据
            log.debug("使用当前租户过滤协商数据，租户键: {}", currentSysTenantKey);
            return contractNegotiationInstanceMapper.countNegotiationsByApplicantWithTenant(userId, currentSysTenantKey, null);
        } else {
            // 如果sysTenantKey为null或空，使用原有逻辑（查询用户有权限的所有租户）
            List<String> userTenantKeys = AuthUtil.getUserTenantKeys();
            log.debug("使用租户列表过滤协商数据，租户键列表: {}", userTenantKeys);
            return contractNegotiationInstanceMapper.countNegotiationsByApplicantWithTenant(userId, null, userTenantKeys);
        }
    }

    @Override
    public Page<ContractDTO> getMyContracts(MyContractQueryDTO dto, Long userId) {
        log.info("查询我的合同，用户ID: {}, 查询类型: {}", userId, dto.getContractType());

        // 优化：使用批量查询版本，大幅提升性能
        try {
            return contractServiceOptimized.getMyContractsOptimized(dto, userId);
        } catch (Exception e) {
            log.error("优化版查询失败，降级到原始查询方式，用户ID: {}, 查询类型: {}", userId, dto.getContractType(), e);
            // 如果优化版本失败，降级到原始查询方式
            return getMyContractsOriginal(dto, userId);
        }
    }

    /**
     * 原始的查询我的合同方法（作为降级方案）
     */
    private Page<ContractDTO> getMyContractsOriginal(MyContractQueryDTO dto, Long userId) {
        log.info("使用原始查询方式，用户ID: {}, 查询类型: {}", userId, dto.getContractType());

        Page<ContractDTO> page = new Page<>(dto.getPageIndex(), dto.getPageSize());
        List<ContractDTO> contracts = new ArrayList<>();

        try {
            switch (dto.getContractType()) {
                case APPLIED:
                    contracts = getMyAppliedContracts(dto, userId);
                    break;
                case APPROVED:
                    contracts = getMyApprovedContracts(dto, userId);
                    break;
                case PENDING:
                    contracts = getMyPendingContracts(dto, userId);
                    break;
                case APPLIED_PENDING:
                    contracts = getMyAppliedPendingContracts(dto, userId);
                    break;
                default:
                    log.warn("未知的查询类型: {}", dto.getContractType());
                    break;
            }

            // 按时间排序（最新的在前面）
            contracts.sort((c1, c2) -> {
                LocalDateTime time1 = c1.getUpdatedAt() != null ? c1.getUpdatedAt() : c1.getCreatedAt();
                LocalDateTime time2 = c2.getUpdatedAt() != null ? c2.getUpdatedAt() : c2.getCreatedAt();

                if (time1 == null && time2 == null) return 0;
                if (time1 == null) return 1;
                if (time2 == null) return -1;

                return time2.compareTo(time1);
            });

            // 关键字过滤
            if (dto.getKeyword() != null && !dto.getKeyword().trim().isEmpty()) {
                String keyword = dto.getKeyword().trim().toLowerCase();
                contracts = contracts.stream()
                        .filter(contract -> matchesKeyword(contract, keyword))
                        .collect(Collectors.toList());
            }

            // 去重处理 - 同一个contractId只保留一条记录（保留updatedAt或createdAt最新的）
            contracts = deduplicateContractsByContractId(contracts);
            log.info("去重后的合同数量: {}", contracts.size());

            // 手动分页
            int total = contracts.size();
            int fromIndex = (dto.getPageIndex() - 1) * dto.getPageSize();
            int toIndex = Math.min(fromIndex + dto.getPageSize(), total);

            List<ContractDTO> pagedContracts = Collections.emptyList();
            if (fromIndex < total) {
                pagedContracts = contracts.subList(fromIndex, toIndex);
            }

            page.setTotal(total);
            page.setRecords(pagedContracts);

            log.info("查询我的合同完成，用户ID: {}, 查询类型: {}, 总数: {}, 返回数: {}",
                    userId, dto.getContractType(), total, pagedContracts.size());

        } catch (Exception e) {
            log.error("查询我的合同失败，用户ID: {}, 查询类型: {}", userId, dto.getContractType(), e);
            page.setTotal(0);
            page.setRecords(Collections.emptyList());
        }

        return page;
    }

    /**
     * 查询我申请的合同
     */
    private List<ContractDTO> getMyAppliedContracts(MyContractQueryDTO dto, Long userId) {
        log.info("查询我申请的合同，用户ID: {}", userId);

        // 添加租户过滤
        LambdaQueryWrapper<ContractEntity> queryWrapper = new LambdaQueryWrapper<ContractEntity>()
                .ne(ContractEntity::getCurrentStatus, "DRAFT")
                .ne(ContractEntity::getCurrentStatus, "IN_NEGOTIATION");

        UserInfo currentUser = AuthUtil.getCurrentUser();
        List<String> userTenantKeys = AuthUtil.getUserTenantKeys();
        if (userTenantKeys != null && !userTenantKeys.isEmpty()) {
            queryWrapper.in(ContractEntity::getSysTenantKey, userTenantKeys);
        } else if (userTenantKeys != null) {
            // 空列表表示没有任何租户权限
            queryWrapper.eq(ContractEntity::getSysTenantKey, "NO_PERMISSION");
        }

        // 1. 查询所有非草稿非协商中的合同（限制当前租户）
        List<ContractEntity> contracts = contractMapper.selectList(queryWrapper);

        if (contracts.isEmpty()) {
            return Collections.emptyList();
        }

        // 2. 获取合同ID列表
        List<Integer> contractIds = contracts.stream()
                .map(ContractEntity::getId)
                .collect(Collectors.toList());

        // 3. 查询申请人字段值为当前用户ID的合同
        // 先通过字段code查询申请人字段ID
        Long applicantFieldId = getFieldIdByCode(SystemFieldsEnum.APPLY_PEOPLE.getCode());
        if (applicantFieldId == null) {
            log.warn("未找到申请人字段配置");
            return Collections.emptyList();
        }
        
        List<ContractFieldValueEntity> applicantFields = contractFieldValueMapper.selectList(
                new LambdaQueryWrapper<ContractFieldValueEntity>()
                        .in(ContractFieldValueEntity::getContractId, contractIds)
                        .eq(ContractFieldValueEntity::getFieldId, applicantFieldId)
                        .eq(ContractFieldValueEntity::getFieldValue, userId.toString())
        );

        // 4. 获取匹配的合同ID列表
        Set<Integer> myContractIds = applicantFields.stream()
                .map(ContractFieldValueEntity::getContractId)
                .collect(Collectors.toSet());

        // 5. 过滤出我申请的合同
        List<ContractEntity> myContracts = contracts.stream()
                .filter(contract -> myContractIds.contains(contract.getId()))
                .collect(Collectors.toList());

        log.info("找到我申请的合同数量: {}", myContracts.size());

        // 6. 转换为ContractDTO（复用现有的合同详情逻辑）
        return myContracts.stream()
                .map(contract -> getContractDetail(contract.getId()))
                .collect(Collectors.toList());
    }

    /**
     * 查询我已审批的合同
     */
    private List<ContractDTO> getMyApprovedContracts(MyContractQueryDTO dto, Long userId) {
        log.info("查询我已审批的合同，用户ID: {}", userId);

        try {
            // 1. 查询我参与的历史任务实例ID
            List<Long> instanceIds = getMyHistoryTaskInstanceIds(userId);

            if (instanceIds.isEmpty()) {
                log.info("未找到用户 {} 参与的历史任务实例", userId);
                return Collections.emptyList();
            }

            // 添加租户过滤 - 修改逻辑：优先使用当前租户，如果为空则使用租户列表
            LambdaQueryWrapper<ContractEntity> queryWrapper = new LambdaQueryWrapper<ContractEntity>()
                    .in(ContractEntity::getApprovalInstanceId, instanceIds);

            UserInfo currentUser = AuthUtil.getCurrentUser();
            String currentSysTenantKey = currentUser != null ? currentUser.getSysTenantKey() : null;

            if (currentSysTenantKey != null && !currentSysTenantKey.trim().isEmpty()) {
                // 如果当前用户有明确的sysTenantKey，只查询该租户下的数据
                queryWrapper.eq(ContractEntity::getSysTenantKey, currentSysTenantKey);
            } else {
                // 如果sysTenantKey为null或空，使用原有逻辑（查询用户有权限的所有租户）
                List<String> userTenantKeys = AuthUtil.getUserTenantKeys();
                if (userTenantKeys != null && !userTenantKeys.isEmpty()) {
                    queryWrapper.in(ContractEntity::getSysTenantKey, userTenantKeys);
                } else if (userTenantKeys != null) {
                    // 空列表表示没有任何租户权限
                    queryWrapper.eq(ContractEntity::getSysTenantKey, "NO_PERMISSION");
                }
            }

            // 2. 根据实例ID查询对应的合同（限制当前租户）
            List<ContractEntity> contracts = contractMapper.selectList(queryWrapper);

            log.info("找到我已审批的合同数量: {}", contracts.size());

            // 3. 转换为ContractDTO
            return contracts.stream()
                    .map(contract -> getContractDetail(contract.getId()))
                    .collect(Collectors.toList());

        } catch (Exception e) {
            log.error("查询我已审批的合同失败，用户ID: {}", userId, e);
            return Collections.emptyList();
        }
    }

    /**
     * 查询我待审批的合同
     */
    private List<ContractDTO> getMyPendingContracts(MyContractQueryDTO dto, Long userId) {
        log.info("查询我待审批的合同，用户ID: {}", userId);

        try {
            // 1. 查询我的待办任务实例ID
            log.info("开始查询用户 {} 的待办任务实例ID", userId);
            List<Long> instanceIds = getMyPendingTaskInstanceIds(userId);
            log.info("查询到用户 {} 的待办任务实例ID数量: {}", userId, instanceIds.size());

            if (instanceIds.isEmpty()) {
                log.info("未找到用户 {} 的待办任务实例", userId);
                return Collections.emptyList();
            }

            // 添加租户过滤 - 修改逻辑：优先使用当前租户，如果为空则使用租户列表
            LambdaQueryWrapper<ContractEntity> queryWrapper = new LambdaQueryWrapper<ContractEntity>()
                    .in(ContractEntity::getApprovalInstanceId, instanceIds)
                    .eq(ContractEntity::getCurrentStatus, "IN_APPROVAL");

            UserInfo currentUser = AuthUtil.getCurrentUser();
            String currentSysTenantKey = currentUser != null ? currentUser.getSysTenantKey() : null;

            if (currentSysTenantKey != null && !currentSysTenantKey.trim().isEmpty()) {
                // 如果当前用户有明确的sysTenantKey，只查询该租户下的数据
                queryWrapper.eq(ContractEntity::getSysTenantKey, currentSysTenantKey);
            } else {
                // 如果sysTenantKey为null或空，使用原有逻辑（查询用户有权限的所有租户）
                List<String> userTenantKeys = AuthUtil.getUserTenantKeys();
                if (userTenantKeys != null && !userTenantKeys.isEmpty()) {
                    queryWrapper.in(ContractEntity::getSysTenantKey, userTenantKeys);
                } else if (userTenantKeys != null) {
                    // 空列表表示没有任何租户权限
                    queryWrapper.eq(ContractEntity::getSysTenantKey, "NO_PERMISSION");
                }
            }

            // 2. 根据实例ID查询对应的合同，并且状态必须是IN_APPROVAL（限制当前租户）
            List<ContractEntity> contracts = contractMapper.selectList(queryWrapper);
            log.info("找到我待审批的合同数量: {}", contracts.size());

            // 3. 获取所有合同的approval_instance_id，查询对应的任务创建时间
            List<Long> approvalInstanceIds = contracts.stream()
                    .map(ContractEntity::getApprovalInstanceId)
                    .filter(Objects::nonNull)
                    .distinct()
                    .collect(Collectors.toList());
            
            log.info("需要查询任务创建时间的实例ID数量: {}", approvalInstanceIds.size());

            // 4. 查询这些实例ID对应的任务创建时间
            Map<Long, LocalDateTime> instanceCreateTimeMap = new HashMap<>();
            if (!approvalInstanceIds.isEmpty()) {
                List<Map<String, Object>> taskCreateTimeData = flowlongMapper.selectTaskCreateTimeByInstanceIds(approvalInstanceIds);
                log.info("查询到任务创建时间数据数量: {}", taskCreateTimeData.size());
                
                for (Map<String, Object> data : taskCreateTimeData) {
                    Object instanceIdObj = data.get("instance_id");
                    Object createTimeObj = data.get("create_time");
                    
                    log.info("SQL查询原始数据: instance_id={} (类型: {}), create_time={} (类型: {})", 
                            instanceIdObj, instanceIdObj != null ? instanceIdObj.getClass().getSimpleName() : "null",
                            createTimeObj, createTimeObj != null ? createTimeObj.getClass().getSimpleName() : "null");
                    
                    if (instanceIdObj != null) {
                        Long instanceId = (Long) instanceIdObj;
                        LocalDateTime createTime = null;
                        
                        if (createTimeObj != null) {
                            if (createTimeObj instanceof LocalDateTime) {
                                createTime = (LocalDateTime) createTimeObj;
                                log.info("时间转换 (LocalDateTime): {} -> {}", createTimeObj, createTime);
                            } else if (createTimeObj instanceof java.sql.Timestamp) {
                                createTime = ((java.sql.Timestamp) createTimeObj).toLocalDateTime();
                                log.info("时间转换 (Timestamp): {} -> {}", createTimeObj, createTime);
                            } else if (createTimeObj instanceof java.util.Date) {
                                createTime = ((java.util.Date) createTimeObj).toInstant()
                                        .atZone(ZoneId.systemDefault())
                                        .toLocalDateTime();
                                log.info("时间转换 (Date): {} -> {}", createTimeObj, createTime);
                            } else {
                                log.warn("未知的时间类型: {}", createTimeObj.getClass().getSimpleName());
                            }
                        } else {
                            log.warn("create_time为null，实例ID: {}", instanceId);
                        }
                        
                        instanceCreateTimeMap.put(instanceId, createTime);
                        log.info("映射存储: 实例ID {} -> 任务创建时间: {}", instanceId, createTime);
                    }
                }
            }

            // 5. 转换为ContractDTO并设置arrivalTime
            log.info("开始转换 {} 个合同为ContractDTO", contracts.size());
            return contracts.stream()
                    .map(contract -> {
                        try {
                            ContractDTO contractDTO = getContractDetail(contract.getId());
                            if (contractDTO != null) {
                                // 设置arrivalTime为对应任务的创建时间
                                LocalDateTime arrivalTime = instanceCreateTimeMap.get(contract.getApprovalInstanceId());
                                contractDTO.setArrivalTime(arrivalTime);
                                log.info("合同ID {} 设置arrivalTime: {}", contract.getId(), arrivalTime);
                            } else {
                                log.warn("合同ID {} 的contractDTO为null", contract.getId());
                            }
                            return contractDTO;
                        } catch (Exception e) {
                            log.error("处理合同详情失败，合同ID: {}", contract.getId(), e);
                            return null;
                        }
                    })
                    .filter(Objects::nonNull)
                    .collect(Collectors.toList());

        } catch (Exception e) {
            log.error("查询我待审批的合同失败，用户ID: {}", userId, e);
            return Collections.emptyList();
        }
    }

    /**
     * 查询我提交的待审批合同
     */
    private List<ContractDTO> getMyAppliedPendingContracts(MyContractQueryDTO dto, Long userId) {
        log.info("查询我提交的待审批合同，用户ID: {}", userId);

        // 添加租户过滤 - 修改逻辑：优先使用当前租户，如果为空则使用租户列表
        LambdaQueryWrapper<ContractEntity> queryWrapper = new LambdaQueryWrapper<ContractEntity>()
                .eq(ContractEntity::getCurrentStatus, "IN_APPROVAL");

        UserInfo currentUser = AuthUtil.getCurrentUser();
        String currentSysTenantKey = currentUser != null ? currentUser.getSysTenantKey() : null;

        if (currentSysTenantKey != null && !currentSysTenantKey.trim().isEmpty()) {
            // 如果当前用户有明确的sysTenantKey，只查询该租户下的数据
            queryWrapper.eq(ContractEntity::getSysTenantKey, currentSysTenantKey);
        } else {
            // 如果sysTenantKey为null或空，使用原有逻辑（查询用户有权限的所有租户）
            List<String> userTenantKeys = AuthUtil.getUserTenantKeys();
            if (userTenantKeys != null && !userTenantKeys.isEmpty()) {
                queryWrapper.in(ContractEntity::getSysTenantKey, userTenantKeys);
            } else if (userTenantKeys != null) {
                // 空列表表示没有任何租户权限
                queryWrapper.eq(ContractEntity::getSysTenantKey, "NO_PERMISSION");
            }
        }

        // 1. 查询状态为IN_APPROVAL（待审批）的合同（限制当前租户）
        List<ContractEntity> contracts = contractMapper.selectList(queryWrapper);

        if (contracts.isEmpty()) {
            log.info("未找到待审批状态的合同");
            return Collections.emptyList();
        }

        // 2. 获取合同ID列表
        List<Integer> contractIds = contracts.stream()
                .map(ContractEntity::getId)
                .collect(Collectors.toList());

        // 3. 查询申请人字段值为当前用户ID的合同
        // 先通过字段code查询申请人字段ID
        Long applicantFieldId = getFieldIdByCode(SystemFieldsEnum.APPLY_PEOPLE.getCode());
        if (applicantFieldId == null) {
            log.warn("未找到申请人字段配置");
            return Collections.emptyList();
        }
        
        List<ContractFieldValueEntity> applicantFields = contractFieldValueMapper.selectList(
                new LambdaQueryWrapper<ContractFieldValueEntity>()
                        .in(ContractFieldValueEntity::getContractId, contractIds)
                        .eq(ContractFieldValueEntity::getFieldId, applicantFieldId)
                        .eq(ContractFieldValueEntity::getFieldValue, userId.toString())
        );

        // 4. 获取匹配的合同ID列表
        Set<Integer> myContractIds = applicantFields.stream()
                .map(ContractFieldValueEntity::getContractId)
                .collect(Collectors.toSet());

        // 5. 过滤出我提交的待审批合同
        List<ContractEntity> myPendingContracts = contracts.stream()
                .filter(contract -> myContractIds.contains(contract.getId()))
                .collect(Collectors.toList());

        log.info("找到我提交的待审批合同数量: {}", myPendingContracts.size());

        // 6. 转换为ContractDTO
        return myPendingContracts.stream()
                .map(contract -> getContractDetail(contract.getId()))
                .collect(Collectors.toList());
    }


    /**
     * 获取我参与的历史任务实例ID列表
     */
    private List<Long> getMyHistoryTaskInstanceIds(Long userId) {
        log.info("开始查询用户 {} 的历史任务实例ID", userId);

        try {
            List<Long> instanceIds = new ArrayList<>();

            // 先获取用户名（username），避免在循环中重复查询
            String userName = getUserNameById(userId);
            log.info("用户 {} 的username: {}", userId, userName);

            // 先查询所有合同的审批实例ID
            List<ContractEntity> allContracts = contractMapper.selectList(
                    new LambdaQueryWrapper<ContractEntity>()
                            .isNotNull(ContractEntity::getApprovalInstanceId)
            );

            log.info("数据库中有审批实例ID的合同数量: {}", allContracts.size());

            for (ContractEntity contract : allContracts) {
                Long approvalInstanceId = contract.getApprovalInstanceId();
                log.info("检查合同 {} 的审批实例 {}", contract.getId(), approvalInstanceId);

                try {
                    // 直接查询该实例的历史任务参与者，无论实例是否完成
                    boolean userParticipated = checkUserParticipatedInHistoryInstance(userId, userName, approvalInstanceId);
                    if (userParticipated) {
                        instanceIds.add(approvalInstanceId);
                        log.info("用户 {} 参与了流程实例: {}，对应合同ID: {}", userId, approvalInstanceId, contract.getId());
                    } else {
                        log.debug("用户 {} 没有参与流程实例: {}，对应合同ID: {}", userId, approvalInstanceId, contract.getId());
                    }
                } catch (Exception e) {
                    log.warn("检查实例 {} 的用户参与情况失败: {}", approvalInstanceId, e.getMessage(), e);
                }
            }

            // 去重
            instanceIds = instanceIds.stream().distinct().collect(Collectors.toList());
            log.info("用户 {} 的历史任务实例ID数量: {}, 实例IDs: {}", userId, instanceIds.size(), instanceIds);

            return instanceIds;

        } catch (Exception e) {
            log.error("获取用户 {} 的历史任务实例ID失败", userId, e);
            return Collections.emptyList();
        }
    }

    /**
     * 获取我的待办任务实例ID列表
     */
    private List<Long> getMyPendingTaskInstanceIds(Long userId) {
        log.info("开始查询用户 {} 的待办任务实例ID", userId);

        try {
            // 直接使用数据库查询获取待办任务实例ID列表
            List<Long> instanceIds = flowlongMapper.selectPendingTaskInstanceIds(userId);

            log.info("用户 {} 的待办任务实例ID数量: {}, 实例IDs: {}", userId, instanceIds.size(), instanceIds);

            return instanceIds;

        } catch (Exception e) {
            log.error("获取用户 {} 的待办任务实例ID失败", userId, e);
            return Collections.emptyList();
        }
    }

    /**
     * 根据用户ID获取用户名（username）
     */
    private String getUserNameById(Long userId) {
        try {
            // 直接查询sys_user表获取username字段
            com.aizuda.boot.modules.system.entity.SysUser sysUser = sysUserService.getById(userId);
            if (sysUser != null) {
                log.info("用户 {} 的username: {}", userId, sysUser.getUsername());
                return sysUser.getUsername();
            }
        } catch (Exception e) {
            log.warn("获取用户 {} 的用户名失败: {}", userId, e.getMessage());
        }
        return null;
    }

    /**
     * 检查用户是否参与了指定的历史流程实例
     */
    private boolean checkUserParticipatedInHistoryInstance(Long userId, String userName, Long instanceId) {
        log.info("开始检查用户 {} 是否参与了流程实例 {}", userId, instanceId);

        try {
            // 直接在SQL中检查用户是否参与了该流程实例
            Integer count = flowlongMapper.selectCountUserParticipatedInInstance(instanceId, userId);
            boolean participated = count != null && count > 0;

            if (participated) {
                log.info("用户 {} 参与了流程实例 {}，参与任务数量: {}", userId, instanceId, count);
            } else {
                log.debug("用户 {} 没有参与流程实例 {}", userId, instanceId);
            }

            return participated;

        } catch (Exception e) {
            log.warn("检查用户 {} 是否参与流程实例 {} 失败: {}", userId, instanceId, e.getMessage(), e);
            return false;
        }
    }

    /**
     * 检查合同是否匹配关键字
     */
    private boolean matchesKeyword(ContractDTO contract, String keyword) {
        if (contract == null || keyword == null || keyword.isEmpty()) {
            return true;
        }

        return (contract.getContractTypeNames() != null &&
                contract.getContractTypeNames().stream().anyMatch(typeName ->
                        typeName != null && typeName.toLowerCase().contains(keyword))) ||
                (contract.getCurrentStatus() != null && contract.getCurrentStatus().toLowerCase().contains(keyword));
    }

    /**
     * 按contractId去重，保留时间最新的记录
     * 优先使用updatedAt，如果为空则使用createdAt
     *
     * @param contracts 合同列表
     * @return 去重后的合同列表
     */
    private List<ContractDTO> deduplicateContractsByContractId(List<ContractDTO> contracts) {
        if (contracts == null || contracts.isEmpty()) {
            return contracts;
        }

        // 按contractId分组，每组保留时间最新的记录
        Map<Integer, ContractDTO> contractMap = new HashMap<>();

        for (ContractDTO contract : contracts) {
            Integer contractId = contract.getId();
            if (contractId == null) {
                continue;
            }

            ContractDTO existingContract = contractMap.get(contractId);
            if (existingContract == null) {
                // 第一次遇到这个contractId，直接添加
                contractMap.put(contractId, contract);
            } else {
                // 已存在相同contractId的记录，比较时间，保留较新的
                LocalDateTime existingTime = getContractTime(existingContract);
                LocalDateTime currentTime = getContractTime(contract);

                if (isNewerTime(currentTime, existingTime)) {
                    // 当前记录更新，替换
                    contractMap.put(contractId, contract);
                    log.debug("去重：合同ID {} 保留更新的记录，时间: {}", contractId, currentTime);
                } else {
                    log.debug("去重：合同ID {} 保留原有记录，时间: {}", contractId, existingTime);
                }
            }
        }

        // 转换为列表并按时间降序排序
        List<ContractDTO> result = new ArrayList<>(contractMap.values());
        result.sort((a, b) -> {
            LocalDateTime timeA = getContractTime(a);
            LocalDateTime timeB = getContractTime(b);

            if (timeA == null && timeB == null) {
                return 0;
            }
            if (timeA == null) {
                return 1; // null排在后面
            }
            if (timeB == null) {
                return -1; // null排在后面
            }
            return timeB.compareTo(timeA); // 降序
        });

        log.info("合同去重完成：原始记录数 {}，去重后记录数 {}", contracts.size(), result.size());
        return result;
    }

    /**
     * 获取合同的时间（优先使用updatedAt，如果为空则使用createdAt）
     */
    private LocalDateTime getContractTime(ContractDTO contract) {
        if (contract.getUpdatedAt() != null) {
            return contract.getUpdatedAt();
        }
        return contract.getCreatedAt();
    }

    /**
     * 判断时间A是否比时间B更新
     */
    private boolean isNewerTime(LocalDateTime timeA, LocalDateTime timeB) {
        if (timeA == null && timeB == null) {
            return false;
        }
        if (timeA == null) {
            return false; // null时间认为不是更新的
        }
        if (timeB == null) {
            return true; // null时间认为任何非null时间都更新
        }
        return timeA.isAfter(timeB);
    }

    /**
     * 处理合同附件确认（字段ID为21）
     * 当合同状态为IN_NEGOTIATION且字段ID为21的数据有变化时，进行相应处理
     *
     * @param contractId    合同ID
     * @param dynamicFields 动态字段集合
     */
    private void processContractAttachmentConfirm(Integer contractId, Map<Long, Object> dynamicFields) {
        try {
            log.info("开始处理合同附件确认，合同ID: {}", contractId);

            // 获取合同附件字段ID
            Long contractAttachmentFieldId = getFieldIdByCode(SystemFieldsEnum.CONTRACT_ATTACHMENT.getCode());
            if (contractAttachmentFieldId == null) {
                log.warn("无法获取合同附件字段ID");
                return;
            }

            // 检查合同附件字段是否存在
            if (!dynamicFields.containsKey(contractAttachmentFieldId)) {
                log.debug("合同附件字段数据不存在，跳过处理");
                return;
            }

            // 获取新的字段值
            Object newValueObj = dynamicFields.get(contractAttachmentFieldId);
            String newValue = newValueObj != null ? newValueObj.toString() : "";

            // 获取原来的字段值
            String oldValue = getOriginalFieldValue(contractId, contractAttachmentFieldId);
            oldValue = oldValue != null ? oldValue : "";

            log.info("合同附件字段 - 原值: {}, 新值: {}", oldValue, newValue);

            // 如果值没有变化，直接返回
            if (oldValue.equals(newValue)) {
                log.debug("合同附件字段的值没有变化，跳过处理");
                return;
            }

            // 解析文件ID数组
            List<Integer> oldFileIds = parseFileIdsAsInteger(oldValue);
            List<Integer> newFileIds = parseFileIdsAsInteger(newValue);

            log.info("原文件ID列表: {}, 新文件ID列表: {}", oldFileIds, newFileIds);

            // 查找新增的文件ID
            List<Integer> addedFileIds = new ArrayList<>(newFileIds);
            addedFileIds.removeAll(oldFileIds);

            // 查找删减的文件ID
            List<Integer> removedFileIds = new ArrayList<>(oldFileIds);
            removedFileIds.removeAll(newFileIds);

            log.info("新增文件ID: {}, 删减文件ID: {}", addedFileIds, removedFileIds);

            // 获取当前合同的审批人ID列表
            List<Long> approverIds = getContractApproverIds(contractId);
            log.info("合同审批人ID列表: {}", approverIds);

            // 处理新增的文件ID
            if (!addedFileIds.isEmpty() && !approverIds.isEmpty()) {
                addAttachmentConfirmRecords(contractId, addedFileIds, approverIds);
            }

            // 处理删减的文件ID
            if (!removedFileIds.isEmpty()) {
                removeAttachmentConfirmRecords(contractId, removedFileIds);
            }

            log.info("合同附件确认处理完成，合同ID: {}", contractId);

        } catch (Exception e) {
            log.error("处理合同附件确认失败，合同ID: {}", contractId, e);
            // 不抛出异常，避免影响主流程
        }
    }

    /**
     * 获取原始字段值
     *
     * @param contractId 合同ID
     * @param fieldId    字段ID
     * @return 字段值
     */
    private String getOriginalFieldValue(Integer contractId, Long fieldId) {
        ContractFieldValueEntity fieldValue = contractFieldValueMapper.selectOne(
                new LambdaQueryWrapper<ContractFieldValueEntity>()
                        .eq(ContractFieldValueEntity::getContractId, contractId)
                        .eq(ContractFieldValueEntity::getFieldId, fieldId)
        );
        return fieldValue != null ? fieldValue.getFieldValue() : null;
    }

    /**
     * 解析文件ID数组字符串为Integer列表
     * 支持格式：[], [1], [1,2], ["1","2"], "1,2" 等
     *
     * @param fileIdStr 文件ID字符串
     * @return 文件ID列表
     */
    private List<Integer> parseFileIdsAsInteger(String fileIdStr) {
        List<Integer> fileIds = new ArrayList<>();

        if (fileIdStr == null || fileIdStr.trim().isEmpty()) {
            return fileIds;
        }

        try {
            // 移除空格
            String trimmed = fileIdStr.trim();

            // 处理空数组情况
            if ("[]".equals(trimmed) || "".equals(trimmed)) {
                return fileIds;
            }

            // 移除方括号
            if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
                trimmed = trimmed.substring(1, trimmed.length() - 1);
            }

            // 按逗号分割
            if (!trimmed.isEmpty()) {
                String[] parts = trimmed.split(",");
                for (String part : parts) {
                    String cleanPart = part.trim()
                            .replaceAll("\"", "")  // 移除可能的双引号
                            .replaceAll("'", "");  // 移除可能的单引号
                    if (!cleanPart.isEmpty()) {
                        fileIds.add(Integer.parseInt(cleanPart));
                    }
                }
            }

        } catch (Exception e) {
            log.error("解析文件ID数组失败: {}", fileIdStr, e);
        }

        return fileIds;
    }

    /**
     * 获取当前合同的审批人ID列表
     * 从contract_negotiation_instance表查询instanceid，
     * 然后从contract_negotiation_participant表查询participanttype为NODE_PARTICIPANT的用户id
     *
     * @param contractId 合同ID
     * @return 审批人ID列表
     */
    private List<Long> getContractApproverIds(Integer contractId) {
        try {
            // 查询协商实例
            ContractNegotiationInstanceEntity instance = contractNegotiationInstanceMapper.selectOne(
                    new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                            .eq(ContractNegotiationInstanceEntity::getContractId, contractId)
                            .orderByDesc(ContractNegotiationInstanceEntity::getCreatedAt)
                            .last("LIMIT 1")
            );

            if (instance == null) {
                log.warn("未找到合同的协商实例，合同ID: {}", contractId);
                return new ArrayList<>();
            }

            // 查询协商参与者
            List<com.aizuda.boot.modules.business.negotiation.entity.ContractNegotiationParticipantEntity> participants =
                    contractNegotiationParticipantMapper.selectList(
                            new LambdaQueryWrapper<com.aizuda.boot.modules.business.negotiation.entity.ContractNegotiationParticipantEntity>()
                                    .eq(com.aizuda.boot.modules.business.negotiation.entity.ContractNegotiationParticipantEntity::getInstanceId, instance.getId())
                                    .eq(com.aizuda.boot.modules.business.negotiation.entity.ContractNegotiationParticipantEntity::getParticipantType, "NODE_PARTICIPANT")
                    );

            return participants.stream()
                    .map(com.aizuda.boot.modules.business.negotiation.entity.ContractNegotiationParticipantEntity::getEmployeeId)
                    .distinct()
                    .collect(Collectors.toList());

        } catch (Exception e) {
            log.error("获取合同审批人ID失败，合同ID: {}", contractId, e);
            return new ArrayList<>();
        }
    }

    /**
     * 添加附件确认记录
     *
     * @param contractId  合同ID
     * @param fileIds     文件ID列表
     * @param approverIds 审批人ID列表
     */
    private void addAttachmentConfirmRecords(Integer contractId, List<Integer> fileIds, List<Long> approverIds) {
        try {
            List<ContractAttachmentConfirmEntity> records = new ArrayList<>();

            for (Integer fileId : fileIds) {
                for (Long approverId : approverIds) {
                    ContractAttachmentConfirmEntity record = new ContractAttachmentConfirmEntity()
                            .setContractId(contractId)
                            .setFileId(fileId)
                            .setUserId(approverId)
                            .setIsConfirmed(0) // 默认未确认
                            .setCreateAt(LocalDateTime.now());
                    records.add(record);
                }
            }

            if (!records.isEmpty()) {
                contractAttachmentConfirmMapper.batchInsert(records);
                log.info("成功添加附件确认记录，合同ID: {}, 记录数: {}", contractId, records.size());
            }

        } catch (Exception e) {
            log.error("添加附件确认记录失败，合同ID: {}", contractId, e);
        }
    }

    /**
     * 删除附件确认记录
     *
     * @param contractId 合同ID
     * @param fileIds    文件ID列表
     */
    private void removeAttachmentConfirmRecords(Integer contractId, List<Integer> fileIds) {
        try {
            int deletedCount = contractAttachmentConfirmMapper.deleteByContractIdAndFileIds(contractId, fileIds);
            log.info("成功删除附件确认记录，合同ID: {}, 删除记录数: {}", contractId, deletedCount);
        } catch (Exception e) {
            log.error("删除附件确认记录失败，合同ID: {}", contractId, e);
        }
    }

    @Override
    public boolean confirmContractAttachment(Integer contractId, Integer fileId) {
        try {
            log.info("开始确认合同附件，合同ID: {}, 文件ID: {}", contractId, fileId);

            // 获取当前用户ID
            UserInfo currentUser = AuthUtil.getCurrentUser();
            if (currentUser == null || currentUser.getId() == null) {
                log.error("获取当前用户失败");
                return false;
            }

            Long userId = currentUser.getId();
            log.info("当前用户ID: {}", userId);

            // 查找对应的确认记录
            ContractAttachmentConfirmEntity confirmRecord = contractAttachmentConfirmMapper.selectOne(
                    new LambdaQueryWrapper<ContractAttachmentConfirmEntity>()
                            .eq(ContractAttachmentConfirmEntity::getContractId, contractId)
                            .eq(ContractAttachmentConfirmEntity::getFileId, fileId)
                            .eq(ContractAttachmentConfirmEntity::getUserId, userId)
            );

            if (confirmRecord == null) {
                log.warn("未找到对应的附件确认记录，合同ID: {}, 文件ID: {}, 用户ID: {}", contractId, fileId, userId);
                return false;
            }

            // 检查是否已经确认过
            if (confirmRecord.getIsConfirmed() != null && confirmRecord.getIsConfirmed() == 1) {
                log.info("附件已经确认过，合同ID: {}, 文件ID: {}, 用户ID: {}", contractId, fileId, userId);
                return true;
            }

            // 更新确认状态
            confirmRecord.setIsConfirmed(1);
            int updateResult = contractAttachmentConfirmMapper.updateById(confirmRecord);

            if (updateResult > 0) {
                log.info("成功确认合同附件，合同ID: {}, 文件ID: {}, 用户ID: {}", contractId, fileId, userId);
                return true;
            } else {
                log.error("更新附件确认状态失败，合同ID: {}, 文件ID: {}, 用户ID: {}", contractId, fileId, userId);
                return false;
            }

        } catch (Exception e) {
            log.error("确认合同附件失败，合同ID: {}, 文件ID: {}", contractId, fileId, e);
            return false;
        }
    }

    @Override
    public boolean checkAllAttachmentsConfirmed(Integer contractId) {
        try {
            log.info("开始检查合同所有附件确认状态，合同ID: {}", contractId);

            // 获取当前用户ID
            UserInfo currentUser = AuthUtil.getCurrentUser();
            if (currentUser == null || currentUser.getId() == null) {
                log.error("获取当前用户失败");
                return false;
            }

            Long userId = currentUser.getId();
            log.info("当前用户ID: {}", userId);

            // 查询当前用户对应的所有附件确认记录
            List<ContractAttachmentConfirmEntity> confirmRecords = contractAttachmentConfirmMapper.selectList(
                    new LambdaQueryWrapper<ContractAttachmentConfirmEntity>()
                            .eq(ContractAttachmentConfirmEntity::getContractId, contractId)
                            .eq(ContractAttachmentConfirmEntity::getUserId, userId)
            );

            log.info("找到 {} 条附件确认记录", confirmRecords.size());

            // 如果没有任何确认记录，说明没有需要确认的附件，返回true
            if (confirmRecords.isEmpty()) {
                log.info("该合同没有需要当前用户确认的附件，合同ID: {}, 用户ID: {}", contractId, userId);
                return true;
            }

            // 检查是否所有记录都已确认
            for (ContractAttachmentConfirmEntity record : confirmRecords) {
                if (record.getIsConfirmed() == null || record.getIsConfirmed() != 1) {
                    log.info("发现未确认的附件，合同ID: {}, 文件ID: {}, 用户ID: {}",
                            contractId, record.getFileId(), userId);
                    return false;
                }
            }

            log.info("所有附件均已确认，合同ID: {}, 用户ID: {}", contractId, userId);
            return true;

        } catch (Exception e) {
            log.error("检查合同附件确认状态失败，合同ID: {}", contractId, e);
            return false;
        }
    }

    @Override
    public boolean sendModificationCompleteNotification(Integer contractId) {
        try {
            log.info("开始发送合同修改完成通知，合同ID: {}", contractId);

            // 获取当前用户信息
            UserInfo currentUser = AuthUtil.getCurrentUser();
            if (currentUser == null || currentUser.getId() == null) {
                log.error("获取当前用户失败");
                return false;
            }

            // 查询协商实例
            ContractNegotiationInstanceEntity instance = contractNegotiationInstanceMapper.selectOne(
                    new LambdaQueryWrapper<ContractNegotiationInstanceEntity>()
                            .eq(ContractNegotiationInstanceEntity::getContractId, contractId)
                            .in(ContractNegotiationInstanceEntity::getNegotiationStatus,
                                    Arrays.asList("IN_NEGOTIATION", "PENDING_NEGOTIATION"))
                            .orderByDesc(ContractNegotiationInstanceEntity::getCreatedAt)
                            .last("LIMIT 1")
            );

            if (instance == null) {
                log.warn("未找到合同的协商实例，合同ID: {}", contractId);
                return false;
            }

            // 查询所有协商参与者
            List<ContractNegotiationParticipantEntity> participants =
                    contractNegotiationParticipantMapper.selectList(
                            new LambdaQueryWrapper<ContractNegotiationParticipantEntity>()
                                    .eq(ContractNegotiationParticipantEntity::getInstanceId, instance.getId())
                    );

            // 收集所有用户ID（参与者 + 发起人）
            Set<Long> userIds = new HashSet<>();

            // 添加所有参与者
            participants.forEach(participant -> {
                if (participant.getEmployeeId() != null) {
                    userIds.add(participant.getEmployeeId());
                }
            });

            // 添加发起人
            if (instance.getApplicantId() != null) {
                userIds.add(instance.getApplicantId());
            }

            // 移除当前用户（发送者自己）
            userIds.remove(currentUser.getId());

            if (userIds.isEmpty()) {
                log.warn("没有找到需要通知的用户，合同ID: {}", contractId);
                return false;
            }

            // 获取合同名称
            String contractName = getOriginalFieldValue(contractId, 5L); // 合同名称字段ID为5
            if (contractName == null || contractName.trim().isEmpty()) {
                contractName = "未知合同";
            }

            // 构建通知内容
            String title = "合同修改完成通知";
            String content = String.format("用户【%s】已完成合同【%s】的修改",
                    currentUser.getNickName() != null ? currentUser.getNickName() : currentUser.getUsername(),
                    contractName);

            // 发布消息事件
            MessageEvent messageEvent = new MessageEvent();
            messageEvent.setTitle(title);
            messageEvent.setContent(content);
            messageEvent.setCreateId(currentUser.getId());
            messageEvent.setCreateBy(currentUser.getNickName() != null ? currentUser.getNickName() : currentUser.getUsername());
            messageEvent.setCategory(2); // 2表示待办消息
            messageEvent.setBusinessId(contractId.longValue());
            messageEvent.setBusinessType("negotiation"); // 协商类型
            messageEvent.setUserIds(new ArrayList<>(userIds));

            // 发布事件，触发飞书通知
            applicationEventPublisher.publishEvent(messageEvent);

            log.info("已发送修改完成通知，合同ID: {}, 通知用户数: {}", contractId, userIds.size());

            return true;

        } catch (Exception e) {
            log.error("发送合同修改完成通知失败，合同ID: {}", contractId, e);
            return false;
        }
    }

    @Override
    public SingleResponse<CounterpartyContractStatusVO> getCounterpartyContractStatus(QueryCounterpartyContractDTO dto) {
        try {
            if (null == dto || null == dto.getContractId() || null == dto.getCertificateId()) {
                return SingleResponse.failure(ResponseCodeEnum.PARAMETER_ERROR.getCode(), ResponseCodeEnum.PARAMETER_ERROR.getMsg());
            }
            CounterpartyContractStatusVO result = new CounterpartyContractStatusVO();
            List<Integer> contractIds = getSameCounterpartyContractIds(dto);
            if (CollectionUtils.isEmpty(contractIds) || contractIds.size() == 1) {
                result.setPendingCount(0);
                result.setSignedCount(0);
                return SingleResponse.of(result);
            }
            contractIds.remove(dto.getContractId());
            List<Integer> signed = this.list(Wrappers.<ContractEntity>lambdaQuery()
                            .in(ContractEntity::getId, contractIds)
                            .in(ContractEntity::getCurrentStatus, ContractStatusEnum.ARCHIVED.getCode(), ContractStatusEnum.CHANGED.getCode())
                            .select(ContractEntity::getId))
                    .stream().map(ContractEntity::getId).toList();
            List<Integer> pending = this.list(Wrappers.<ContractEntity>lambdaQuery()
                            .in(ContractEntity::getId, contractIds)
                            .in(ContractEntity::getCurrentStatus, ContractStatusEnum.IN_APPROVAL.getCode(), ContractStatusEnum.IN_NEGOTIATION.getCode(), ContractStatusEnum.IN_SIGNING.getCode(),
                                    ContractStatusEnum.IN_ARCHIVING.getCode(), ContractStatusEnum.IN_CHANGE.getCode(), ContractStatusEnum.SEALED.getCode(), ContractStatusEnum.IN_TERMINATION.getCode())
                            .select(ContractEntity::getId))
                    .stream().map(ContractEntity::getId).toList();
            result.setSignedCount(signed.size());
            result.setPendingCount(pending.size());
            return SingleResponse.of(result);
        } catch (Exception e) {
            log.error("获取交易方与我方签订合同数量失败", e);
            return SingleResponse.failure(ResponseCodeEnum.SYS_ERROR.getCode(), ResponseCodeEnum.SYS_ERROR.getMsg());
        }
    }

    @Override
    public SingleResponse<List<CounterpartyContractVO>> getSingleCounterpartyContracts(QueryCounterpartyContractDTO dto) {
        try {
            if (null == dto || null == dto.getContractId() || null == dto.getCertificateId()) {
                return SingleResponse.failure(ResponseCodeEnum.PARAMETER_ERROR.getCode(), ResponseCodeEnum.PARAMETER_ERROR.getMsg());
            }
            ArrayList<CounterpartyContractVO> result = new ArrayList<>();
            List<Integer> contractIds = getSameCounterpartyContractIds(dto);
            if (CollectionUtils.isEmpty(contractIds) || contractIds.size() == 1) {
                return SingleResponse.of(result);
            }
            contractIds.remove(dto.getContractId());
            List<Integer> signed = this.list(Wrappers.<ContractEntity>lambdaQuery()
                            .in(ContractEntity::getId, contractIds)
                            .in(ContractEntity::getCurrentStatus, ContractStatusEnum.ARCHIVED.getCode(), ContractStatusEnum.CHANGED.getCode())
                            .select(ContractEntity::getId))
                    .stream().map(ContractEntity::getId).toList();
            result = getCounterpartyContract(signed, dto.getCertificateId());
            return SingleResponse.of(result);
        } catch (Exception e) {
            log.error("查询交易方与我方签订的合同失败", e);
            return SingleResponse.failure(ResponseCodeEnum.SYS_ERROR.getCode(), ResponseCodeEnum.SYS_ERROR.getMsg());
        }
    }

    @Override
    public SingleResponse<List<CounterpartyContractVO>> getPendingCounterpartyContracts(QueryCounterpartyContractDTO dto) {
        try {
            if (null == dto || null == dto.getContractId() || null == dto.getCertificateId()) {
                return SingleResponse.failure(ResponseCodeEnum.PARAMETER_ERROR.getCode(), ResponseCodeEnum.PARAMETER_ERROR.getMsg());
            }
            ArrayList<CounterpartyContractVO> result = new ArrayList<>();
            List<Integer> contractIds = getSameCounterpartyContractIds(dto);
            if (CollectionUtils.isEmpty(contractIds) || contractIds.size() == 1) {
                return SingleResponse.of(result);
            }
            contractIds.remove(dto.getContractId());
            List<Integer> pending = this.list(Wrappers.<ContractEntity>lambdaQuery()
                            .in(ContractEntity::getId, contractIds)
                            .in(ContractEntity::getCurrentStatus, ContractStatusEnum.IN_APPROVAL.getCode(), ContractStatusEnum.IN_NEGOTIATION.getCode(), ContractStatusEnum.IN_SIGNING.getCode(),
                                    ContractStatusEnum.IN_ARCHIVING.getCode(), ContractStatusEnum.IN_CHANGE.getCode(), ContractStatusEnum.SEALED.getCode(), ContractStatusEnum.IN_TERMINATION.getCode())
                            .select(ContractEntity::getId))
                    .stream().map(ContractEntity::getId).toList();
            result = getCounterpartyContract(pending, dto.getCertificateId());
            return SingleResponse.of(result);
        } catch (Exception e) {
            log.error("查询交易方与我方签订的合同失败", e);
            return SingleResponse.failure(ResponseCodeEnum.SYS_ERROR.getCode(), ResponseCodeEnum.SYS_ERROR.getMsg());
        }
    }


    /**
     * 获取同时包含指定对方ID和我方ID的合同ID列表
     *
     * @param dto 查询条件
     * @return 合同ID列表
     */
    private List<Integer> getSameCounterpartyContractIds(QueryCounterpartyContractDTO dto) {
        String certificateId = dto.getCertificateId();
        CounterpartyInfoEntity counterpartyInfo = counterpartyInfoMapper.selectOne(Wrappers.<CounterpartyInfoEntity>lambdaQuery()
                .eq(CounterpartyInfoEntity::getCertificateId, certificateId)
                .last("limit 1"));
        if (null == counterpartyInfo){
            return new ArrayList<>();
        }
        Integer oppositeId = counterpartyInfo.getId();
        Integer contractId = dto.getContractId();
        List<Integer> ourIds = new ArrayList<>();
        List<Integer> contractIds = new ArrayList<>();

        // 获取当前合同的我方ID列表
        String ourValue = contractFieldValueMapper.getFieldValueByCode(contractId, SystemFieldsEnum.OUR.getCode());
        if (StringUtils.hasText(ourValue)) {
            try {
                // 解析JSON数组格式的我方ID列表
                ourIds.addAll(JSON.parseArray(ourValue, Integer.class));
            } catch (Exception e) {
                log.warn("解析我方ID列表失败，合同ID: {}, 值: {}", contractId, ourValue, e);
            }
        }

        // 如果我方ID列表为空，直接返回空列表
        if (ourIds.isEmpty()) {
            log.info("我方ID列表为空，合同ID: {}", contractId);
            return contractIds;
        }

        ContractFieldEntity opposite = contractFieldMapper.selectOne(Wrappers.<ContractFieldEntity>lambdaQuery()
                .eq(ContractFieldEntity::getCode, SystemFieldsEnum.OPPOSITE.getCode())
                .select(ContractFieldEntity::getId)
                .last("limit 1"));
        if (null == opposite) {
            log.warn("查询对方字段失败，合同ID: {}", contractId);
            return contractIds;
        }

        ContractFieldEntity our = contractFieldMapper.selectOne(Wrappers.<ContractFieldEntity>lambdaQuery()
                .eq(ContractFieldEntity::getCode, SystemFieldsEnum.OUR.getCode())
                .select(ContractFieldEntity::getId)
                .last("limit 1"));
        if (null == our) {
            log.warn("查询我方字段失败，合同ID: {}", contractId);
            return contractIds;
        }

        // 查询所有合同的对方和我方字段值
        List<ContractFieldValueEntity> counterpartyFields = contractFieldValueMapper.selectList(
                new LambdaQueryWrapper<ContractFieldValueEntity>()
                        .eq(ContractFieldValueEntity::getFieldId, opposite.getId())
        );

        List<ContractFieldValueEntity> ourFields = contractFieldValueMapper.selectList(
                new LambdaQueryWrapper<ContractFieldValueEntity>()
                        .eq(ContractFieldValueEntity::getFieldId, our.getId())
        );

        // 构建合同ID到对方ID列表的映射
        Map<Integer, List<Integer>> contractToCounterpartyMap = new HashMap<>();
        for (ContractFieldValueEntity field : counterpartyFields) {
            if (field.getContractId() != null && StringUtils.hasText(field.getFieldValue())) {
                try {
                    List<Integer> counterpartyIds = JSON.parseArray(field.getFieldValue(), Integer.class);
                    contractToCounterpartyMap.put(field.getContractId(), counterpartyIds);
                } catch (Exception e) {
                    log.warn("解析合同对方ID列表失败，合同ID: {}, 值: {}", field.getContractId(), field.getFieldValue(), e);
                }
            }
        }

        // 构建合同ID到我方ID列表的映射
        Map<Integer, List<Integer>> contractToOurMap = new HashMap<>();
        for (ContractFieldValueEntity field : ourFields) {
            if (field.getContractId() != null && StringUtils.hasText(field.getFieldValue())) {
                try {
                    List<Integer> ourPartyIds = JSON.parseArray(field.getFieldValue(), Integer.class);
                    contractToOurMap.put(field.getContractId(), ourPartyIds);
                } catch (Exception e) {
                    log.warn("解析合同我方ID列表失败，合同ID: {}, 值: {}", field.getContractId(), field.getFieldValue(), e);
                }
            }
        }

        // 筛选同时包含指定对方ID和我方ID的合同
        for (Map.Entry<Integer, List<Integer>> entry : contractToCounterpartyMap.entrySet()) {
            Integer contractIdKey = entry.getKey();
            List<Integer> counterpartyIds = entry.getValue();

            // 检查是否包含指定的对方ID
            if (counterpartyIds.contains(oppositeId)) {
                // 检查是否包含指定的我方ID
                List<Integer> contractOurIds = contractToOurMap.get(contractIdKey);
                if (CollectionUtils.isNotEmpty(contractOurIds) && contractOurIds.stream().anyMatch(ourIds::contains)) {
                    contractIds.add(contractIdKey);
                }
            }
        }

        log.info("查询到符合条件的合同数量: {}, 对方ID: {}, 我方ID列表: {}", contractIds.size(), oppositeId, ourIds);
        return contractIds;
    }

    /**
     * 根据合同ID列表获取交易方合同信息
     *
     * @param contractIds 合同ID列表
     * @param certificateId
     * @return 交易方合同信息列表
     */
    private ArrayList<CounterpartyContractVO> getCounterpartyContract(List<Integer> contractIds, String certificateId) {
        if (CollectionUtils.isEmpty(contractIds)) {
            return new ArrayList<>();
        }

        CounterpartyInfoEntity opposite = counterpartyInfoMapper.selectOne(Wrappers.<CounterpartyInfoEntity>lambdaQuery()
                .eq(CounterpartyInfoEntity::getCertificateId, certificateId)
                .last("limit 1"));
        if (null == opposite) {
            return new ArrayList<>();
        }

        // 查询合同列表
        List<ContractEntity> contracts = this.listByIds(contractIds);
        if (CollectionUtils.isEmpty(contracts)) {
            return new ArrayList<>();
        }

        List<String> fieldCode = Arrays.asList(SystemFieldsEnum.CONTRACT_NAME.getCode(), SystemFieldsEnum.CONTRACT_NUMBER.getCode(), SystemFieldsEnum.CONTRACT_TYPE.getCode(), SystemFieldsEnum.APPLY_PEOPLE.getCode());

        Map<String, Long> fieldMap = contractFieldMapper.selectList(Wrappers.<ContractFieldEntity>lambdaQuery()
                        .in(ContractFieldEntity::getCode, fieldCode)
                        .select(ContractFieldEntity::getId, ContractFieldEntity::getCode))
                .stream().collect(Collectors.toMap(ContractFieldEntity::getCode, ContractFieldEntity::getId, (existing, replacement) -> existing));

        // 查询所有合同的字段值
        if (fieldMap.isEmpty()) {
            log.warn("未找到指定的字段定义: {}", fieldCode);
            return new ArrayList<>();
        }

        List<ContractFieldValueEntity> fieldValues = contractFieldValueMapper.selectList(
                new LambdaQueryWrapper<ContractFieldValueEntity>()
                        .in(ContractFieldValueEntity::getContractId, contractIds)
                        .in(ContractFieldValueEntity::getFieldId, fieldMap.values())
        );

        // 按合同ID分组字段值
        Map<Integer, List<ContractFieldValueEntity>> contractFieldMap = fieldValues.stream()
                .collect(Collectors.groupingBy(ContractFieldValueEntity::getContractId));

        // 收集需要查询的用户ID
        Set<Long> userIds = new HashSet<>();

        for (List<ContractFieldValueEntity> values : contractFieldMap.values()) {
            if (values != null) {
                for (ContractFieldValueEntity value : values) {
                    if (value != null && fieldMap.get(SystemFieldsEnum.APPLY_PEOPLE.getCode()) != null && fieldMap.get(SystemFieldsEnum.APPLY_PEOPLE.getCode()).equals(value.getFieldId()) && StringUtils.hasText(value.getFieldValue())) {
                        try {
                            userIds.add(Long.valueOf(value.getFieldValue()));
                        } catch (NumberFormatException e) {
                            log.warn("申请人字段值不是有效数字: {}", value.getFieldValue());
                        }
                    }
                }
            }
        }

        // 查询用户信息
        Map<Long, SysUser> userMap = new HashMap<>();
        if (!userIds.isEmpty()) {
            List<SysUser> users = sysUserService.listByIds(new ArrayList<>(userIds));
            userMap = users.stream().collect(Collectors.toMap(SysUser::getId, user -> user, (existing, replacement) -> existing));
        }

        Map<Long, Long> userDepartmentMap = new HashMap<>();
        if (!userIds.isEmpty()) {
            List<SysUserDepartment> userDepartments = sysUserDepartmentService.lambdaQuery()
                    .in(SysUserDepartment::getUserId, userIds)
                    .eq(SysUserDepartment::getIsMain, 1)
                    .select(SysUserDepartment::getUserId, SysUserDepartment::getDepartmentId)
                    .list();
            userDepartmentMap = userDepartments.stream().collect(Collectors.toMap(SysUserDepartment::getUserId, SysUserDepartment::getDepartmentId, (existing, replacement) -> existing));
        }

        Map<Long, SysDepartment> departmentMap = new HashMap<>();
        if (!userDepartmentMap.values().isEmpty()) {
            List<SysDepartment> departments = sysDepartmentService.lambdaQuery()
                    .in(SysDepartment::getId, userDepartmentMap.values())
                    .list();
            departmentMap = departments.stream().collect(Collectors.toMap(SysDepartment::getId, item -> item, (existing, replacement) -> existing));
        }

        // 收集合同类型ID
        Set<Integer> contractTypeIds = new HashSet<>();
        for (List<ContractFieldValueEntity> values : contractFieldMap.values()) {
            if (values != null) {
                for (ContractFieldValueEntity value : values) {
                    if (value != null && fieldMap.get(SystemFieldsEnum.CONTRACT_TYPE.getCode()) != null && fieldMap.get(SystemFieldsEnum.CONTRACT_TYPE.getCode()).equals(value.getFieldId()) && StringUtils.hasText(value.getFieldValue())) {
                        try {
                            contractTypeIds.add(Integer.valueOf(value.getFieldValue()));
                        } catch (NumberFormatException e) {
                            log.warn("合同类型字段值不是有效数字: {}", value.getFieldValue());
                        }
                    }
                }
            }
        }

        // 一次性查询所有合同类型
        Map<Integer, ContractTypeEntity> contractTypeMap = new HashMap<>();
        if (!contractTypeIds.isEmpty()) {
            List<ContractTypeEntity> contractTypes = contractTypeMapper.selectBatchIds(contractTypeIds);
            contractTypeMap = contractTypes.stream().collect(Collectors.toMap(ContractTypeEntity::getId, item -> item, (existing, replacement) -> existing));
        }

        // 构建结果
        ArrayList<CounterpartyContractVO> result = new ArrayList<>();
        for (ContractEntity contract : contracts) {
            if (contract == null) {
                continue;
            }

            CounterpartyContractVO vo = new CounterpartyContractVO();
            vo.setContractId(contract.getId());
            vo.setOppositeName(opposite.getCounterpartyName());

            // 获取该合同的字段值
            List<ContractFieldValueEntity> values = contractFieldMap.get(contract.getId());
            if (values != null) {
                for (ContractFieldValueEntity value : values) {
                    if (value == null) {
                        continue;
                    }

                    Long fieldId = value.getFieldId();
                    String fieldValue = value.getFieldValue();

                    if (fieldMap.get(SystemFieldsEnum.CONTRACT_NAME.getCode()) != null && fieldMap.get(SystemFieldsEnum.CONTRACT_NAME.getCode()).equals(fieldId)) {
                        vo.setContractName(fieldValue);
                    } else if (fieldMap.get(SystemFieldsEnum.CONTRACT_NUMBER.getCode()) != null && fieldMap.get(SystemFieldsEnum.CONTRACT_NUMBER.getCode()).equals(fieldId)) {
                        vo.setContractNo(fieldValue);
                    } else if (fieldMap.get(SystemFieldsEnum.CONTRACT_TYPE.getCode()) != null && fieldMap.get(SystemFieldsEnum.CONTRACT_TYPE.getCode()).equals(fieldId)) {
                        // 从已查询的合同类型映射中获取合同类型名称
                        if (StringUtils.hasText(fieldValue)) {
                            try {
                                ContractTypeEntity contractType = contractTypeMap.get(Integer.valueOf(fieldValue));
                                if (contractType != null) {
                                    vo.setContractType(contractType.getTypeName());
                                }
                            } catch (NumberFormatException e) {
                                log.warn("合同类型字段值不是有效数字: {}", fieldValue);
                            }
                        }
                    } else if (fieldMap.get(SystemFieldsEnum.APPLY_PEOPLE.getCode()) != null && fieldMap.get(SystemFieldsEnum.APPLY_PEOPLE.getCode()).equals(fieldId)) {
                        if (StringUtils.hasText(fieldValue)) {
                            try {
                                Long userId = Long.valueOf(fieldValue);
                                SysUser user = userMap.get(userId);
                                if (user != null) {
                                    vo.setApplyUser(user.getRealName());

                                    // 设置部门信息
                                    Long departmentId = userDepartmentMap.get(userId);
                                    if (departmentId != null) {
                                        SysDepartment department = departmentMap.get(departmentId);
                                        if (department != null) {
                                            vo.setDepartment(department.getName());
                                        }
                                    }
                                }
                            } catch (NumberFormatException e) {
                                log.warn("申请人字段值不是有效数字: {}", fieldValue);
                            }
                        }
                    }
                }
            }

            result.add(vo);
        }

        return result;
    }

    /**
     * 获取用户部门（优先返回主部门，没有主部门则返回任意一个部门）
     */
    private String getUserDepartment(Long userId) {
        log.info("【合同详情】开始查询用户部门，userId: {}", userId);

        try {
            if (userId == null) {
                log.warn("【合同详情】userId为空，无法查询部门");
                return null;
            }

            // 先查找主部门
            log.info("【合同详情】查询主部门，userId: {}", userId);
            SysUserDepartment mainUserDept = sysUserDepartmentService.lambdaQuery()
                    .eq(SysUserDepartment::getUserId, userId)
                    .eq(SysUserDepartment::getIsMain, 1)
                    .one();

            log.info("【合同详情】主部门查询结果，userId: {}, mainUserDept: {}", userId,
                    mainUserDept != null ? mainUserDept.getDepartmentId() : "null");

            if (mainUserDept != null) {
                // 直接获取主部门信息，不过滤租户
                log.info("【合同详情】查询主部门详情，userId: {}, departmentId: {}", userId, mainUserDept.getDepartmentId());
                SysDepartment mainDepartment = sysDepartmentMapper.selectOne(
                        Wrappers.<SysDepartment>lambdaQuery()
                                .eq(SysDepartment::getId, mainUserDept.getDepartmentId())
                                .eq(SysDepartment::getStatus, 1)
                );

                log.info("【合同详情】主部门详情查询结果，userId: {}, department: {}", userId,
                        mainDepartment != null ? mainDepartment.getName() : "null");

                if (mainDepartment != null) {
                    log.info("【合同详情】找到用户主部门，userId: {}, 部门名称: {}", userId, mainDepartment.getName());
                    return mainDepartment.getName();
                }
            }

            log.info("【合同详情】用户没有主部门，查找任意一个部门，userId: {}", userId);

            // 如果没有主部门，查找任意一个部门
            SysUserDepartment anyUserDept = sysUserDepartmentService.lambdaQuery()
                    .eq(SysUserDepartment::getUserId, userId)
                    .last("LIMIT 1")
                    .one();

            log.info("【合同详情】任意部门查询结果，userId: {}, anyUserDept: {}", userId,
                    anyUserDept != null ? anyUserDept.getDepartmentId() : "null");

            if (anyUserDept != null) {
                log.info("【合同详情】查询任意部门详情，userId: {}, departmentId: {}", userId, anyUserDept.getDepartmentId());
                SysDepartment department = sysDepartmentMapper.selectOne(
                        Wrappers.<SysDepartment>lambdaQuery()
                                .eq(SysDepartment::getId, anyUserDept.getDepartmentId())
                                .eq(SysDepartment::getStatus, 1)
                );

                log.info("【合同详情】任意部门详情查询结果，userId: {}, department: {}", userId,
                        department != null ? department.getName() : "null");

                if (department != null) {
                    log.info("【合同详情】找到用户其他部门，userId: {}, 部门名称: {}", userId, department.getName());
                    return department.getName();
                }
            }

            log.warn("【合同详情】用户没有有效部门，userId: {}", userId);
            return null;
        } catch (Exception e) {
            log.error("【合同详情】查询用户部门失败，userId: {}", userId, e);
            return null;
        }
    }

    @Override
    public Boolean isBackdatedContract(Integer contractId) {
        try {
            log.info("开始判断倒签合同，合同ID: {}", contractId);

            // 1. 查询合同基本信息，获取创建时间
            ContractEntity contract = getById(contractId);
            if (contract == null) {
                log.warn("合同不存在，合同ID: {}", contractId);
                throw new RuntimeException("合同不存在");
            }

            if (contract.getCreatedAt() == null) {
                log.warn("合同创建时间为空，默认认为是倒签合同，合同ID: {}", contractId);
                return true;
            }

            log.info("合同创建时间: {}", contract.getCreatedAt());

            // 2. 查询申请时间字段（code = apply_date）
            ContractFieldEntity applyDateField = contractFieldMapper.selectOne(
                    new LambdaQueryWrapper<ContractFieldEntity>()
                            .eq(ContractFieldEntity::getCode, "apply_date")
                            .select(ContractFieldEntity::getId)
                            .last("LIMIT 1")
            );

            if (applyDateField == null) {
                log.warn("未找到申请时间字段配置（code=apply_date），默认认为是倒签合同，合同ID: {}", contractId);
                return true;
            }

            // 3. 查询合同的申请时间字段值
            ContractFieldValueEntity applyDateValue = contractFieldValueMapper.selectOne(
                    new LambdaQueryWrapper<ContractFieldValueEntity>()
                            .eq(ContractFieldValueEntity::getContractId, contractId)
                            .eq(ContractFieldValueEntity::getFieldId, applyDateField.getId())
                            .last("LIMIT 1")
            );

            if (applyDateValue == null || applyDateValue.getFieldValue() == null || applyDateValue.getFieldValue().trim().isEmpty()) {
                log.warn("未找到申请时间字段值，默认认为是倒签合同，合同ID: {}, 字段ID: {}", contractId, applyDateField.getId());
                return true;
            }

            // 4. 解析申请时间
            String applyDateStr = applyDateValue.getFieldValue().trim();
            log.info("申请时间字符串: {}", applyDateStr);

            try {
                // 尝试解析申请时间（支持多种格式）
                java.time.LocalDateTime applyDateTime = parseDateTime(applyDateStr);
                java.time.LocalDateTime createDateTime = contract.getCreatedAt();

                log.info("申请时间: {}, 创建时间: {}", applyDateTime, createDateTime);

                // 5. 判断是否为倒签：申请时间 < 创建时间
                boolean isBackdated = applyDateTime.isBefore(createDateTime);

                log.info("倒签合同判断结果，合同ID: {}, 是否倒签: {}", contractId, isBackdated);
                return isBackdated;

            } catch (Exception e) {
                log.error("解析申请时间失败，默认认为是倒签合同，合同ID: {}, 申请时间字符串: {}", contractId, applyDateStr, e);
                return true;
            }

        } catch (Exception e) {
            log.error("判断倒签合同失败，合同ID: {}", contractId, e);
            throw new RuntimeException("判断倒签合同失败: " + e.getMessage());
        }
    }

    /**
     * 应用模糊搜索过滤
     */
    private List<ContractEntity> applyFuzzySearchFilter(List<ContractEntity> contracts, String keyword) {
        if (keyword == null || keyword.trim().isEmpty()) {
            return contracts;
        }

        String searchKeyword = keyword.trim().toLowerCase();
        log.info("应用模糊搜索过滤，关键词: {}", searchKeyword);

        return contracts.stream().filter(contract -> {
            try {
                // 查询该合同的动态字段值
                List<ContractFieldValueEntity> fieldValues = contractFieldValueMapper.selectByContractId(contract.getId());
                Map<String, String> fieldValueMap = new HashMap<>();

                for (ContractFieldValueEntity fieldValue : fieldValues) {
                    // 查询字段配置获取字段code
                    ContractFieldEntity field = contractFieldMapper.selectById(fieldValue.getFieldId());
                    if (field != null) {
                        fieldValueMap.put(field.getCode(), fieldValue.getFieldValue());
                    }
                }

                // 1. 合同名称匹配
                String contractName = fieldValueMap.get("contract_name");
                if (contractName != null && contractName.toLowerCase().contains(searchKeyword)) {
                    return true;
                }

                // 2. 申请人名称匹配
                String applyPeopleId = fieldValueMap.get("apply_people");
                if (applyPeopleId != null) {
                    try {
                        SysUser applicant = sysUserService.getById(Long.parseLong(applyPeopleId));
                        if (applicant != null && applicant.getNickName() != null &&
                            applicant.getNickName().toLowerCase().contains(searchKeyword)) {
                            return true;
                        }
                    } catch (Exception e) {
                        log.warn("解析申请人ID失败: {}", applyPeopleId);
                    }
                }

                // 3. 合同编码匹配（字段code为contract_number）
                String contractCode = fieldValueMap.get("contract_number");
                if (contractCode != null && contractCode.toLowerCase().contains(searchKeyword)) {
                    return true;
                }

                // 4. 交易方名称匹配
                String oppositeIds = fieldValueMap.get("opposite");
                if (oppositeIds != null) {
                    try {
                        // 解析交易方ID数组 [1,2]
                        String cleanIds = oppositeIds.replaceAll("[\\[\\]\\s]", "");
                        if (!cleanIds.isEmpty()) {
                            String[] idArray = cleanIds.split(",");
                            for (String idStr : idArray) {
                                try {
                                    CounterpartyInfoEntity counterparty = counterpartyService.getById(Integer.parseInt(idStr.trim()));
                                    if (counterparty != null && counterparty.getCounterpartyName() != null &&
                                        counterparty.getCounterpartyName().toLowerCase().contains(searchKeyword)) {
                                        return true;
                                    }
                                } catch (Exception e) {
                                    log.warn("解析交易方ID失败: {}", idStr);
                                }
                            }
                        }
                    } catch (Exception e) {
                        log.warn("解析交易方ID数组失败: {}", oppositeIds);
                    }
                }

                return false;

            } catch (Exception e) {
                log.error("模糊搜索过滤合同失败，合同ID: {}", contract.getId(), e);
                return false;
            }
        }).collect(Collectors.toList());
    }

    /**
     * 转换为简化列表VO
     */
    private List<ContractSimpleListVO> convertToSimpleListVO(List<ContractEntity> contracts) {
        return contracts.stream().map(contract -> {
            try {
                ContractSimpleListVO vo = new ContractSimpleListVO();
                vo.setContractId(contract.getId());
                vo.setContractStatus(contract.getCurrentStatus());

                // 查询动态字段值
                List<ContractFieldValueEntity> fieldValues = contractFieldValueMapper.selectByContractId(contract.getId());
                Map<String, String> fieldValueMap = new HashMap<>();

                for (ContractFieldValueEntity fieldValue : fieldValues) {
                    ContractFieldEntity field = contractFieldMapper.selectById(fieldValue.getFieldId());
                    if (field != null) {
                        fieldValueMap.put(field.getCode(), fieldValue.getFieldValue());
                    }
                }

                // 设置合同名称
                vo.setContractName(fieldValueMap.get("contract_name"));

                // 设置合同编码
                vo.setContractCode(fieldValueMap.get("contract_number"));

                // 设置申请人信息
                String applyPeopleId = fieldValueMap.get("apply_people");
                if (applyPeopleId != null) {
                    try {
                        SysUser applicant = sysUserService.getById(Long.parseLong(applyPeopleId));
                        if (applicant != null) {
                            vo.setApplicantName(applicant.getNickName());
                            vo.setApplicantAvatar(applicant.getAvatar());
                        }
                    } catch (Exception e) {
                        log.warn("获取申请人信息失败，ID: {}", applyPeopleId);
                    }
                }

                // 设置交易方名称列表（返回所有交易方）
                String oppositeIds = fieldValueMap.get("opposite");
                List<String> counterpartyNames = new ArrayList<>();
                if (oppositeIds != null) {
                    try {
                        String cleanIds = oppositeIds.replaceAll("[\\[\\]\\s]", "");
                        if (!cleanIds.isEmpty()) {
                            String[] idArray = cleanIds.split(",");
                            for (String idStr : idArray) {
                                try {
                                    CounterpartyInfoEntity counterparty = counterpartyService.getById(Integer.parseInt(idStr.trim()));
                                    if (counterparty != null && counterparty.getCounterpartyName() != null) {
                                        counterpartyNames.add(counterparty.getCounterpartyName());
                                    }
                                } catch (Exception e) {
                                    log.warn("解析交易方ID失败: {}", idStr);
                                }
                            }
                        }
                    } catch (Exception e) {
                        log.warn("获取交易方信息失败，IDs: {}", oppositeIds);
                    }
                }
                vo.setCounterpartyNames(counterpartyNames);

                return vo;

            } catch (Exception e) {
                log.error("转换合同VO失败，合同ID: {}", contract.getId(), e);
                return null;
            }
        }).filter(vo -> vo != null).collect(Collectors.toList());
    }

    @Override
    public Page<ContractSimpleListVO> getSimpleContractList(ContractSimpleListReqDTO request) {
        try {
            log.info("开始查询简化合同列表，请求参数: {}", request);

            // 1. 构建基础查询条件（复用 queryType=0 的逻辑）
            LambdaQueryWrapper<ContractEntity> queryWrapper = new LambdaQueryWrapper<>();

            // 应用租户权限过滤（复用现有逻辑）
            UserInfo currentUser = AuthUtil.getCurrentUser();
            String currentSysTenantKey = currentUser != null ? currentUser.getSysTenantKey() : null;

            if (currentSysTenantKey != null && !currentSysTenantKey.trim().isEmpty()) {
                // 如果当前用户有明确的sysTenantKey，只查询该租户下的数据
                queryWrapper.eq(ContractEntity::getSysTenantKey, currentSysTenantKey);
                log.debug("使用当前租户过滤合同列表：{}", currentSysTenantKey);
            } else {
                // 如果sysTenantKey为null或空，使用原有逻辑（查询用户有权限的所有租户）
                List<String> userTenantKeys = AuthUtil.getUserTenantKeys();
                if (userTenantKeys != null && !userTenantKeys.isEmpty()) {
                    queryWrapper.in(ContractEntity::getSysTenantKey, userTenantKeys);
                    log.debug("使用租户列表过滤合同列表：{}", userTenantKeys);
                } else if (userTenantKeys == null) {
                    // null 表示超级管理员，不限制租户
                    log.debug("超级管理员访问，不限制租户");
                } else {
                    // 空列表表示没有任何租户权限
                    queryWrapper.eq(ContractEntity::getSysTenantKey, "NO_PERMISSION");
                    log.warn("用户没有任何租户权限");
                }
            }

            // 应用数据权限过滤
            if (currentUser != null && currentUser.getId() != null) {
                applyDataPermissionFilter(queryWrapper, currentUser.getId());
            }

            // 排除协商中的合同和草稿状态的合同（与 queryType=0 逻辑保持一致）
            queryWrapper.ne(ContractEntity::getCurrentStatus, "IN_NEGOTIATION")
                        .ne(ContractEntity::getCurrentStatus, "DRAFT");

            // 合同状态过滤
            if (request.getContractStatus() != null && !request.getContractStatus().trim().isEmpty()) {
                queryWrapper.eq(ContractEntity::getCurrentStatus, request.getContractStatus());
            }

            // 按更新时间倒序排列
            queryWrapper.orderByDesc(ContractEntity::getUpdatedAt);

            // 2. 查询符合基础条件的合同
            List<ContractEntity> allContracts = contractMapper.selectList(queryWrapper);
            log.info("基础查询到 {} 个合同", allContracts.size());

            // 3. 应用模糊搜索过滤
            List<ContractEntity> filteredContracts = applyFuzzySearchFilter(allContracts, request.getKeyword());
            log.info("模糊搜索过滤后剩余 {} 个合同", filteredContracts.size());

            // 4. 手动分页
            int total = filteredContracts.size();
            int pageNo = request.getPageNo() != null ? request.getPageNo() : 1;
            int pageSize = request.getPageSize() != null ? request.getPageSize() : 10;
            int startIndex = (pageNo - 1) * pageSize;
            int endIndex = Math.min(startIndex + pageSize, total);

            List<ContractEntity> pagedContracts = filteredContracts.subList(startIndex, endIndex);

            // 5. 转换为 VO
            List<ContractSimpleListVO> contractVOs = convertToSimpleListVO(pagedContracts);

            // 6. 构建分页结果
            Page<ContractSimpleListVO> page = new Page<>(pageNo, pageSize, total);
            page.setRecords(contractVOs);

            log.info("简化合同列表查询完成，返回 {} 条记录，总计 {} 条", contractVOs.size(), total);
            return page;

        } catch (Exception e) {
            log.error("查询简化合同列表失败", e);
            throw new RuntimeException("查询合同列表失败: " + e.getMessage());
        }
    }

    @Override
    public Boolean canDownloadWord(String fileId) {
        try {
            log.info("开始判断是否可以下载Word文件，文件ID: {}", fileId);

            // 1. 首先判断是否为管理员
            boolean isAdmin = AuthUtil.isSuperAdmin();
            if (!isAdmin) {
                log.info("用户不是管理员，无法下载Word文件，文件ID: {}", fileId);
                return false;
            }

            // 2. 如果是管理员，判断文件是否为Word文档
            SingleResponse<FileVO> fileResponse = fileInfoService.getFileInfoById(fileId);
            if (!fileResponse.isSuccess() || fileResponse.getData() == null) {
                log.warn("文件不存在或获取文件信息失败，文件ID: {}", fileId);
                return false;
            }

            FileVO fileInfo = fileResponse.getData();
            String fileName = fileInfo.getFileName();
            
            // 3. 判断文件是否为Word文档格式
            boolean isWordFile = FileConversionUtil.isDocxFile(fileName);
            
            log.info("判断Word文件下载权限完成，文件ID: {}, 是否管理员: {}, 文件名: {}, 是否Word文档: {}, 最终结果: {}", 
                    fileId, isAdmin, fileName, isWordFile, isWordFile);
            
            return isWordFile;

        } catch (Exception e) {
            log.error("判断Word文件下载权限异常，文件ID: {}", fileId, e);
            throw new RuntimeException("判断下载权限失败: " + e.getMessage());
        }
    }

    /**
     * 根据字段代码获取字段ID
     * 
     * @param fieldCode 字段代码
     * @return 字段ID，如果找不到返回null
     */
    public Long getFieldIdByCode(String fieldCode) {
        try {
            ContractFieldEntity field = contractFieldService.getOne(
                    Wrappers.<ContractFieldEntity>lambdaQuery()
                            .eq(ContractFieldEntity::getCode, fieldCode)
                            .select(ContractFieldEntity::getId)
                            .last("limit 1")
            );
            return field != null ? field.getId() : null;
        } catch (Exception e) {
            log.error("根据字段代码获取字段ID失败，字段代码: {}", fieldCode, e);
            return null;
        }
    }

}

